duocode 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +36 -0
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/ast/context.d.ts +16 -0
- package/dist/ast/context.js +37 -0
- package/dist/ast/context.js.map +1 -0
- package/dist/ast/diff.d.ts +27 -0
- package/dist/ast/diff.js +44 -0
- package/dist/ast/diff.js.map +1 -0
- package/dist/ast/locks.d.ts +47 -0
- package/dist/ast/locks.js +88 -0
- package/dist/ast/locks.js.map +1 -0
- package/dist/ast/merge.d.ts +22 -0
- package/dist/ast/merge.js +120 -0
- package/dist/ast/merge.js.map +1 -0
- package/dist/ast/ownership.d.ts +31 -0
- package/dist/ast/ownership.js +111 -0
- package/dist/ast/ownership.js.map +1 -0
- package/dist/ast/parser.d.ts +44 -0
- package/dist/ast/parser.js +134 -0
- package/dist/ast/parser.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +423 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.js +63 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/duo.d.ts +9 -0
- package/dist/commands/duo.js +285 -0
- package/dist/commands/duo.js.map +1 -0
- package/dist/commands/github.d.ts +2 -0
- package/dist/commands/github.js +85 -0
- package/dist/commands/github.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +33 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/negotiation.d.ts +2 -0
- package/dist/commands/negotiation.js +160 -0
- package/dist/commands/negotiation.js.map +1 -0
- package/dist/commands/repl_commands.d.ts +26 -0
- package/dist/commands/repl_commands.js +226 -0
- package/dist/commands/repl_commands.js.map +1 -0
- package/dist/commands/shell.d.ts +1 -0
- package/dist/commands/shell.js +110 -0
- package/dist/commands/shell.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +231 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/task.d.ts +2 -0
- package/dist/commands/task.js +215 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/config/loader.d.ts +193 -0
- package/dist/config/loader.js +106 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/context/project_context.d.ts +79 -0
- package/dist/context/project_context.js +292 -0
- package/dist/context/project_context.js.map +1 -0
- package/dist/context/token_budget.d.ts +35 -0
- package/dist/context/token_budget.js +81 -0
- package/dist/context/token_budget.js.map +1 -0
- package/dist/db/queries.d.ts +121 -0
- package/dist/db/queries.js +109 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +110 -0
- package/dist/db/schema.js +346 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/duo/duo_orchestrator.d.ts +50 -0
- package/dist/duo/duo_orchestrator.js +510 -0
- package/dist/duo/duo_orchestrator.js.map +1 -0
- package/dist/duo/duo_session.d.ts +47 -0
- package/dist/duo/duo_session.js +127 -0
- package/dist/duo/duo_session.js.map +1 -0
- package/dist/duo/duo_types.d.ts +168 -0
- package/dist/duo/duo_types.js +53 -0
- package/dist/duo/duo_types.js.map +1 -0
- package/dist/duo/session_store.d.ts +71 -0
- package/dist/duo/session_store.js +177 -0
- package/dist/duo/session_store.js.map +1 -0
- package/dist/git/worktree.d.ts +21 -0
- package/dist/git/worktree.js +86 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/github/cache.d.ts +23 -0
- package/dist/github/cache.js +67 -0
- package/dist/github/cache.js.map +1 -0
- package/dist/github/issues.d.ts +17 -0
- package/dist/github/issues.js +93 -0
- package/dist/github/issues.js.map +1 -0
- package/dist/github/mcp_client.d.ts +57 -0
- package/dist/github/mcp_client.js +214 -0
- package/dist/github/mcp_client.js.map +1 -0
- package/dist/github/sync.d.ts +11 -0
- package/dist/github/sync.js +65 -0
- package/dist/github/sync.js.map +1 -0
- package/dist/github/webhook.d.ts +25 -0
- package/dist/github/webhook.js +197 -0
- package/dist/github/webhook.js.map +1 -0
- package/dist/negotiation/index.d.ts +1 -0
- package/dist/negotiation/index.js +2 -0
- package/dist/negotiation/index.js.map +1 -0
- package/dist/negotiation/protocol.d.ts +62 -0
- package/dist/negotiation/protocol.js +188 -0
- package/dist/negotiation/protocol.js.map +1 -0
- package/dist/orchestrator/complexity_scorer.d.ts +2 -0
- package/dist/orchestrator/complexity_scorer.js +79 -0
- package/dist/orchestrator/complexity_scorer.js.map +1 -0
- package/dist/orchestrator/dependency_graph.d.ts +7 -0
- package/dist/orchestrator/dependency_graph.js +73 -0
- package/dist/orchestrator/dependency_graph.js.map +1 -0
- package/dist/orchestrator/intent_parser.d.ts +11 -0
- package/dist/orchestrator/intent_parser.js +116 -0
- package/dist/orchestrator/intent_parser.js.map +1 -0
- package/dist/orchestrator/task_runner.d.ts +56 -0
- package/dist/orchestrator/task_runner.js +181 -0
- package/dist/orchestrator/task_runner.js.map +1 -0
- package/dist/orchestrator/types.d.ts +44 -0
- package/dist/orchestrator/types.js +21 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +12 -0
- package/dist/providers/anthropic.js +258 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/auction.d.ts +42 -0
- package/dist/providers/auction.js +190 -0
- package/dist/providers/auction.js.map +1 -0
- package/dist/providers/base.d.ts +103 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/cost_tracker.d.ts +45 -0
- package/dist/providers/cost_tracker.js +111 -0
- package/dist/providers/cost_tracker.js.map +1 -0
- package/dist/providers/duo_pair_router.d.ts +11 -0
- package/dist/providers/duo_pair_router.js +67 -0
- package/dist/providers/duo_pair_router.js.map +1 -0
- package/dist/providers/factory.d.ts +7 -0
- package/dist/providers/factory.js +130 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/grading_rubric.d.ts +37 -0
- package/dist/providers/grading_rubric.js +238 -0
- package/dist/providers/grading_rubric.js.map +1 -0
- package/dist/providers/openai.d.ts +12 -0
- package/dist/providers/openai.js +229 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +14 -0
- package/dist/providers/openrouter.js +178 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/performance_tracker.d.ts +21 -0
- package/dist/providers/performance_tracker.js +63 -0
- package/dist/providers/performance_tracker.js.map +1 -0
- package/dist/providers/registry_loader.d.ts +6 -0
- package/dist/providers/registry_loader.js +54 -0
- package/dist/providers/registry_loader.js.map +1 -0
- package/dist/providers/retry.d.ts +66 -0
- package/dist/providers/retry.js +203 -0
- package/dist/providers/retry.js.map +1 -0
- package/dist/providers/role_scorer.d.ts +16 -0
- package/dist/providers/role_scorer.js +16 -0
- package/dist/providers/role_scorer.js.map +1 -0
- package/dist/providers/router.d.ts +84 -0
- package/dist/providers/router.js +542 -0
- package/dist/providers/router.js.map +1 -0
- package/dist/security/credentials.d.ts +6 -0
- package/dist/security/credentials.js +16 -0
- package/dist/security/credentials.js.map +1 -0
- package/dist/setup/browser.d.ts +1 -0
- package/dist/setup/browser.js +12 -0
- package/dist/setup/browser.js.map +1 -0
- package/dist/setup/global_config.d.ts +14 -0
- package/dist/setup/global_config.js +54 -0
- package/dist/setup/global_config.js.map +1 -0
- package/dist/setup/wizard.d.ts +2 -0
- package/dist/setup/wizard.js +206 -0
- package/dist/setup/wizard.js.map +1 -0
- package/dist/tools/agent_loop.d.ts +38 -0
- package/dist/tools/agent_loop.js +72 -0
- package/dist/tools/agent_loop.js.map +1 -0
- package/dist/tools/approval.d.ts +64 -0
- package/dist/tools/approval.js +172 -0
- package/dist/tools/approval.js.map +1 -0
- package/dist/tools/checkpoint.d.ts +65 -0
- package/dist/tools/checkpoint.js +342 -0
- package/dist/tools/checkpoint.js.map +1 -0
- package/dist/tools/definitions.d.ts +13 -0
- package/dist/tools/definitions.js +103 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/diff_display.d.ts +46 -0
- package/dist/tools/diff_display.js +298 -0
- package/dist/tools/diff_display.js.map +1 -0
- package/dist/tools/executor.d.ts +12 -0
- package/dist/tools/executor.js +340 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/permissions.d.ts +17 -0
- package/dist/tools/permissions.js +139 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/tool_types.d.ts +48 -0
- package/dist/tools/tool_types.js +7 -0
- package/dist/tools/tool_types.js.map +1 -0
- package/dist/ui/banner.d.ts +4 -0
- package/dist/ui/banner.js +104 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/callbacks.d.ts +30 -0
- package/dist/ui/callbacks.js +132 -0
- package/dist/ui/callbacks.js.map +1 -0
- package/dist/ui/colors.d.ts +14 -0
- package/dist/ui/colors.js +28 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/ui/dashboard.d.ts +51 -0
- package/dist/ui/dashboard.js +181 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/ui/leaderboard.d.ts +16 -0
- package/dist/ui/leaderboard.js +43 -0
- package/dist/ui/leaderboard.js.map +1 -0
- package/dist/ui/logger.d.ts +28 -0
- package/dist/ui/logger.js +117 -0
- package/dist/ui/logger.js.map +1 -0
- package/dist/ui/progress.d.ts +16 -0
- package/dist/ui/progress.js +62 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/tokenizer.d.ts +5 -0
- package/dist/ui/tokenizer.js +54 -0
- package/dist/ui/tokenizer.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart context gathering — scans the project, builds a tree summary,
|
|
3
|
+
* and identifies relevant files based on the task prompt.
|
|
4
|
+
*/
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
const DEFAULT_IGNORE_DIRS = new Set([
|
|
8
|
+
"node_modules", ".git", ".duocode", "dist", "build", "out",
|
|
9
|
+
".next", ".nuxt", ".svelte-kit", "__pycache__", ".venv",
|
|
10
|
+
"venv", "env", ".tox", "coverage", ".nyc_output", ".cache",
|
|
11
|
+
".parcel-cache", ".turbo", ".vercel", ".output",
|
|
12
|
+
]);
|
|
13
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
14
|
+
/\.lock$/,
|
|
15
|
+
/package-lock\.json$/,
|
|
16
|
+
/yarn\.lock$/,
|
|
17
|
+
/pnpm-lock\.yaml$/,
|
|
18
|
+
/\.min\.(js|css)$/,
|
|
19
|
+
/\.map$/,
|
|
20
|
+
/\.d\.ts$/,
|
|
21
|
+
/\.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|mp4|mp3|webm|webp)$/i,
|
|
22
|
+
/\.(zip|tar|gz|bz2|7z|rar)$/i,
|
|
23
|
+
/\.(exe|dll|so|dylib|bin)$/i,
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Scan a project directory and return a flat list of files.
|
|
27
|
+
* Respects .gitignore-style patterns and depth limits.
|
|
28
|
+
*/
|
|
29
|
+
export function scanProjectTree(rootDir, config = {}) {
|
|
30
|
+
const maxDepth = config.maxDepth ?? 4;
|
|
31
|
+
const maxFiles = config.maxTreeFiles ?? 200;
|
|
32
|
+
const ignoreDirs = new Set([...DEFAULT_IGNORE_DIRS, ...(config.ignoreDirs ?? [])]);
|
|
33
|
+
const ignorePatterns = [
|
|
34
|
+
...DEFAULT_IGNORE_PATTERNS,
|
|
35
|
+
...(config.ignorePatterns ?? []).map((p) => new RegExp(p)),
|
|
36
|
+
];
|
|
37
|
+
const files = [];
|
|
38
|
+
let truncated = false;
|
|
39
|
+
function walk(dir, depth) {
|
|
40
|
+
if (depth > maxDepth || files.length >= maxFiles) {
|
|
41
|
+
truncated = true;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let entries;
|
|
45
|
+
try {
|
|
46
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return; // Permission denied or similar
|
|
50
|
+
}
|
|
51
|
+
// Sort for deterministic output
|
|
52
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (files.length >= maxFiles) {
|
|
55
|
+
truncated = true;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (entry.name.startsWith(".") && entry.name !== ".env.example")
|
|
59
|
+
continue;
|
|
60
|
+
const fullPath = path.join(dir, entry.name);
|
|
61
|
+
const relativePath = path.relative(rootDir, fullPath);
|
|
62
|
+
if (entry.isDirectory()) {
|
|
63
|
+
if (ignoreDirs.has(entry.name))
|
|
64
|
+
continue;
|
|
65
|
+
walk(fullPath, depth + 1);
|
|
66
|
+
}
|
|
67
|
+
else if (entry.isFile()) {
|
|
68
|
+
if (ignorePatterns.some((p) => p.test(entry.name)))
|
|
69
|
+
continue;
|
|
70
|
+
let stat;
|
|
71
|
+
try {
|
|
72
|
+
stat = fs.statSync(fullPath);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
files.push({
|
|
78
|
+
relativePath,
|
|
79
|
+
absolutePath: fullPath,
|
|
80
|
+
sizeBytes: stat.size,
|
|
81
|
+
ext: path.extname(entry.name).toLowerCase(),
|
|
82
|
+
mtimeMs: stat.mtimeMs,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
walk(rootDir, 0);
|
|
88
|
+
return {
|
|
89
|
+
root: rootDir,
|
|
90
|
+
files,
|
|
91
|
+
totalFiles: files.length,
|
|
92
|
+
truncated,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// ── Tree Rendering ────────────────────────────────────────────────
|
|
96
|
+
/**
|
|
97
|
+
* Render a directory tree as a concise indented string.
|
|
98
|
+
*/
|
|
99
|
+
export function renderTree(tree) {
|
|
100
|
+
const byDir = new Map();
|
|
101
|
+
for (const file of tree.files) {
|
|
102
|
+
const dir = path.dirname(file.relativePath);
|
|
103
|
+
const list = byDir.get(dir) ?? [];
|
|
104
|
+
list.push(path.basename(file.relativePath));
|
|
105
|
+
byDir.set(dir, list);
|
|
106
|
+
}
|
|
107
|
+
const lines = [`${path.basename(tree.root)}/`];
|
|
108
|
+
const sortedDirs = [...byDir.keys()].sort();
|
|
109
|
+
for (const dir of sortedDirs) {
|
|
110
|
+
const depth = dir === "." ? 0 : dir.split(path.sep).length;
|
|
111
|
+
const indent = " ".repeat(depth);
|
|
112
|
+
const filesList = byDir.get(dir);
|
|
113
|
+
if (dir !== ".") {
|
|
114
|
+
lines.push(`${indent}${path.basename(dir)}/`);
|
|
115
|
+
}
|
|
116
|
+
const fileIndent = " ".repeat(depth + 1);
|
|
117
|
+
for (const f of filesList) {
|
|
118
|
+
lines.push(`${fileIndent}${f}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (tree.truncated) {
|
|
122
|
+
lines.push(` ... (truncated at ${tree.totalFiles} files)`);
|
|
123
|
+
}
|
|
124
|
+
return lines.join("\n");
|
|
125
|
+
}
|
|
126
|
+
// ── Relevance Detection ───────────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* Score files by relevance to a prompt using keyword matching.
|
|
129
|
+
* Returns files sorted by relevance score (highest first).
|
|
130
|
+
*/
|
|
131
|
+
export function rankFilesByRelevance(files, prompt) {
|
|
132
|
+
const words = extractKeywords(prompt);
|
|
133
|
+
if (words.length === 0)
|
|
134
|
+
return [];
|
|
135
|
+
return files
|
|
136
|
+
.map((file) => {
|
|
137
|
+
let score = 0;
|
|
138
|
+
const fileParts = file.relativePath.toLowerCase().split(/[/\\.]/);
|
|
139
|
+
for (const word of words) {
|
|
140
|
+
// Exact filename match
|
|
141
|
+
if (fileParts.some((p) => p === word))
|
|
142
|
+
score += 3;
|
|
143
|
+
// Partial filename match
|
|
144
|
+
else if (fileParts.some((p) => p.includes(word)))
|
|
145
|
+
score += 1;
|
|
146
|
+
}
|
|
147
|
+
// Boost source files over configs
|
|
148
|
+
if (isSrcFile(file.ext))
|
|
149
|
+
score += 0.5;
|
|
150
|
+
// Boost test files when prompt mentions testing
|
|
151
|
+
if (isTestFile(file.relativePath) && words.some((w) => /test|spec|assert/.test(w))) {
|
|
152
|
+
score += 2;
|
|
153
|
+
}
|
|
154
|
+
return { ...file, relevanceScore: score };
|
|
155
|
+
})
|
|
156
|
+
.filter((f) => f.relevanceScore > 0)
|
|
157
|
+
.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
158
|
+
}
|
|
159
|
+
function extractKeywords(prompt) {
|
|
160
|
+
const stopWords = new Set([
|
|
161
|
+
"the", "a", "an", "is", "are", "was", "were", "be", "been",
|
|
162
|
+
"being", "have", "has", "had", "do", "does", "did", "will",
|
|
163
|
+
"would", "could", "should", "may", "might", "shall", "can",
|
|
164
|
+
"to", "of", "in", "for", "on", "with", "at", "by", "from",
|
|
165
|
+
"as", "into", "through", "during", "before", "after", "this",
|
|
166
|
+
"that", "these", "those", "it", "its", "and", "or", "but",
|
|
167
|
+
"not", "no", "if", "then", "else", "when", "up", "out",
|
|
168
|
+
"about", "each", "which", "their", "what", "so", "some",
|
|
169
|
+
"all", "any", "most", "other", "than", "too", "very",
|
|
170
|
+
"just", "only", "also", "how", "where", "why", "who",
|
|
171
|
+
"add", "create", "make", "build", "write", "implement",
|
|
172
|
+
"fix", "update", "change", "modify", "please", "need",
|
|
173
|
+
"want", "file", "code",
|
|
174
|
+
]);
|
|
175
|
+
return prompt
|
|
176
|
+
.toLowerCase()
|
|
177
|
+
.replace(/[^a-z0-9_-]/g, " ")
|
|
178
|
+
.split(/\s+/)
|
|
179
|
+
.filter((w) => w.length > 2 && !stopWords.has(w));
|
|
180
|
+
}
|
|
181
|
+
function isSrcFile(ext) {
|
|
182
|
+
return [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".c", ".cpp", ".h"].includes(ext);
|
|
183
|
+
}
|
|
184
|
+
function isTestFile(relativePath) {
|
|
185
|
+
return /\.(test|spec)\.(ts|tsx|js|jsx|py)$/.test(relativePath)
|
|
186
|
+
|| relativePath.includes("__tests__")
|
|
187
|
+
|| relativePath.startsWith("tests/")
|
|
188
|
+
|| relativePath.startsWith("test/");
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Build smart context from a project directory and task prompt.
|
|
192
|
+
* Includes:
|
|
193
|
+
* 1. Project tree summary
|
|
194
|
+
* 2. Contents of relevant files (within token budget)
|
|
195
|
+
* 3. Explicit @ mentions
|
|
196
|
+
*/
|
|
197
|
+
export function buildProjectContext(rootDir, prompt, config = {}) {
|
|
198
|
+
const maxChars = config.maxContextChars ?? 60000;
|
|
199
|
+
const maxFileSize = config.maxFileSizeBytes ?? 100000;
|
|
200
|
+
// 1. Scan tree
|
|
201
|
+
const tree = scanProjectTree(rootDir, config);
|
|
202
|
+
const treeSummary = renderTree(tree);
|
|
203
|
+
// 2. Extract @ mentions
|
|
204
|
+
const mentions = extractMentions(prompt, rootDir);
|
|
205
|
+
// 3. Rank remaining files by relevance
|
|
206
|
+
const ranked = rankFilesByRelevance(tree.files.filter((f) => !mentions.some((m) => m.absolutePath === f.absolutePath)), prompt);
|
|
207
|
+
// 4. Assemble context within budget
|
|
208
|
+
const parts = [];
|
|
209
|
+
const includedFiles = [];
|
|
210
|
+
const droppedFiles = [];
|
|
211
|
+
// Project tree (always included, usually ~2-4KB)
|
|
212
|
+
const treeSection = `## Project Structure\n\`\`\`\n${treeSummary}\n\`\`\`\n`;
|
|
213
|
+
parts.push(treeSection);
|
|
214
|
+
let charBudget = maxChars - treeSection.length;
|
|
215
|
+
// @ mentioned files first (highest priority)
|
|
216
|
+
for (const mention of mentions) {
|
|
217
|
+
if (charBudget <= 0)
|
|
218
|
+
break;
|
|
219
|
+
const content = safeReadFile(mention.absolutePath, maxFileSize);
|
|
220
|
+
if (!content)
|
|
221
|
+
continue;
|
|
222
|
+
if (content.length > charBudget) {
|
|
223
|
+
droppedFiles.push(mention.relativePath);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const section = `## ${mention.relativePath}\n\`\`\`\n${content}\n\`\`\`\n`;
|
|
227
|
+
parts.push(section);
|
|
228
|
+
includedFiles.push({ path: mention.relativePath, content, reason: "@ mention" });
|
|
229
|
+
charBudget -= section.length;
|
|
230
|
+
}
|
|
231
|
+
// Relevant files next
|
|
232
|
+
for (const file of ranked) {
|
|
233
|
+
if (charBudget <= 0)
|
|
234
|
+
break;
|
|
235
|
+
const content = safeReadFile(file.absolutePath, maxFileSize);
|
|
236
|
+
if (!content)
|
|
237
|
+
continue;
|
|
238
|
+
if (content.length > charBudget) {
|
|
239
|
+
droppedFiles.push(file.relativePath);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const section = `## ${file.relativePath}\n\`\`\`\n${content}\n\`\`\`\n`;
|
|
243
|
+
parts.push(section);
|
|
244
|
+
includedFiles.push({
|
|
245
|
+
path: file.relativePath,
|
|
246
|
+
content,
|
|
247
|
+
reason: `relevance: ${file.relevanceScore.toFixed(1)}`,
|
|
248
|
+
});
|
|
249
|
+
charBudget -= section.length;
|
|
250
|
+
}
|
|
251
|
+
const systemContext = parts.join("\n");
|
|
252
|
+
return {
|
|
253
|
+
systemContext,
|
|
254
|
+
includedFiles,
|
|
255
|
+
totalChars: systemContext.length,
|
|
256
|
+
droppedFiles,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// ── @ Mention Parsing ─────────────────────────────────────────────
|
|
260
|
+
export function extractMentions(prompt, rootDir) {
|
|
261
|
+
const mentions = [];
|
|
262
|
+
// Match @path/to/file.ext or @"path with spaces/file.ext"
|
|
263
|
+
const regex = /@(?:"([^"]+)"|(\S+\.\w+))/g;
|
|
264
|
+
let match;
|
|
265
|
+
while ((match = regex.exec(prompt)) !== null) {
|
|
266
|
+
const relativePath = match[1] ?? match[2];
|
|
267
|
+
const absolutePath = path.resolve(rootDir, relativePath);
|
|
268
|
+
if (fs.existsSync(absolutePath) && fs.statSync(absolutePath).isFile()) {
|
|
269
|
+
mentions.push({ relativePath, absolutePath });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return mentions;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Strip @mentions from prompt text so the model sees clean input.
|
|
276
|
+
* Returns the prompt with @path references removed.
|
|
277
|
+
*/
|
|
278
|
+
export function stripMentions(prompt) {
|
|
279
|
+
return prompt.replace(/@(?:"[^"]+"|(\S+\.\w+))/g, "").replace(/\s{2,}/g, " ").trim();
|
|
280
|
+
}
|
|
281
|
+
function safeReadFile(filePath, maxBytes) {
|
|
282
|
+
try {
|
|
283
|
+
const stat = fs.statSync(filePath);
|
|
284
|
+
if (stat.size > maxBytes)
|
|
285
|
+
return null;
|
|
286
|
+
return fs.readFileSync(filePath, "utf8");
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=project_context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_context.js","sourceRoot":"","sources":["../../src/context/project_context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token budget estimation and context truncation.
|
|
3
|
+
*
|
|
4
|
+
* Uses a simple chars/3.5 heuristic for token estimation.
|
|
5
|
+
* Provides truncation strategies: oldest history → lowest relevance files → individual file trimming.
|
|
6
|
+
*/
|
|
7
|
+
export declare function estimateTokens(text: string): number;
|
|
8
|
+
export interface TokenBudgetInfo {
|
|
9
|
+
contextWindow: number;
|
|
10
|
+
maxOutputTokens: number;
|
|
11
|
+
systemPromptTokens: number;
|
|
12
|
+
conversationTokens: number;
|
|
13
|
+
fileContextTokens: number;
|
|
14
|
+
availableForUser: number;
|
|
15
|
+
utilizationPct: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function computeBudget(opts: {
|
|
18
|
+
contextWindow: number;
|
|
19
|
+
maxOutputTokens: number;
|
|
20
|
+
systemPrompt: string;
|
|
21
|
+
conversationHistory: string;
|
|
22
|
+
fileContext: string;
|
|
23
|
+
}): TokenBudgetInfo;
|
|
24
|
+
export declare function truncateConversationHistory(history: string, maxTokens: number): string;
|
|
25
|
+
export interface FileContextEntry {
|
|
26
|
+
path: string;
|
|
27
|
+
content: string;
|
|
28
|
+
relevance: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function truncateFileContext(files: FileContextEntry[], maxTokens: number): {
|
|
31
|
+
kept: FileContextEntry[];
|
|
32
|
+
dropped: string[];
|
|
33
|
+
};
|
|
34
|
+
export declare function truncateFileContent(content: string, maxLines: number): string;
|
|
35
|
+
export declare function formatBudgetStatus(budget: TokenBudgetInfo): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token budget estimation and context truncation.
|
|
3
|
+
*
|
|
4
|
+
* Uses a simple chars/3.5 heuristic for token estimation.
|
|
5
|
+
* Provides truncation strategies: oldest history → lowest relevance files → individual file trimming.
|
|
6
|
+
*/
|
|
7
|
+
// ── Estimation ──────────────────────────────────────────────────
|
|
8
|
+
export function estimateTokens(text) {
|
|
9
|
+
return Math.ceil(text.length / 3.5);
|
|
10
|
+
}
|
|
11
|
+
export function computeBudget(opts) {
|
|
12
|
+
const systemPromptTokens = estimateTokens(opts.systemPrompt);
|
|
13
|
+
const conversationTokens = estimateTokens(opts.conversationHistory);
|
|
14
|
+
const fileContextTokens = estimateTokens(opts.fileContext);
|
|
15
|
+
const used = systemPromptTokens + conversationTokens + fileContextTokens + opts.maxOutputTokens;
|
|
16
|
+
const availableForUser = Math.max(0, opts.contextWindow - used);
|
|
17
|
+
const utilizationPct = Math.min(100, (used / opts.contextWindow) * 100);
|
|
18
|
+
return {
|
|
19
|
+
contextWindow: opts.contextWindow,
|
|
20
|
+
maxOutputTokens: opts.maxOutputTokens,
|
|
21
|
+
systemPromptTokens,
|
|
22
|
+
conversationTokens,
|
|
23
|
+
fileContextTokens,
|
|
24
|
+
availableForUser,
|
|
25
|
+
utilizationPct,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// ── Truncation: conversation history (oldest turns first) ───────
|
|
29
|
+
export function truncateConversationHistory(history, maxTokens) {
|
|
30
|
+
if (!history)
|
|
31
|
+
return history;
|
|
32
|
+
const currentTokens = estimateTokens(history);
|
|
33
|
+
if (currentTokens <= maxTokens)
|
|
34
|
+
return history;
|
|
35
|
+
// Split by turn markers and drop oldest
|
|
36
|
+
const turns = history.split(/(?=### Turn \d+)/);
|
|
37
|
+
while (turns.length > 1 && estimateTokens(turns.join("")) > maxTokens) {
|
|
38
|
+
turns.shift();
|
|
39
|
+
}
|
|
40
|
+
const result = turns.join("");
|
|
41
|
+
if (estimateTokens(result) > maxTokens) {
|
|
42
|
+
const targetChars = Math.floor(maxTokens * 3.5);
|
|
43
|
+
return "[...earlier context truncated]\n" + result.slice(-targetChars);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
export function truncateFileContext(files, maxTokens) {
|
|
48
|
+
const sorted = [...files].sort((a, b) => b.relevance - a.relevance);
|
|
49
|
+
const kept = [];
|
|
50
|
+
const dropped = [];
|
|
51
|
+
let usedTokens = 0;
|
|
52
|
+
for (const file of sorted) {
|
|
53
|
+
const fileTokens = estimateTokens(file.content);
|
|
54
|
+
if (usedTokens + fileTokens <= maxTokens) {
|
|
55
|
+
kept.push(file);
|
|
56
|
+
usedTokens += fileTokens;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
dropped.push(file.path);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { kept, dropped };
|
|
63
|
+
}
|
|
64
|
+
// ── Truncation: individual file content (keep head + tail) ──────
|
|
65
|
+
export function truncateFileContent(content, maxLines) {
|
|
66
|
+
const lines = content.split("\n");
|
|
67
|
+
if (lines.length <= maxLines)
|
|
68
|
+
return content;
|
|
69
|
+
const keepEach = Math.floor(maxLines / 2);
|
|
70
|
+
const head = lines.slice(0, keepEach);
|
|
71
|
+
const tail = lines.slice(-keepEach);
|
|
72
|
+
const dropped = lines.length - keepEach * 2;
|
|
73
|
+
return [...head, `\n... (${dropped} lines omitted) ...\n`, ...tail].join("\n");
|
|
74
|
+
}
|
|
75
|
+
// ── Display ─────────────────────────────────────────────────────
|
|
76
|
+
export function formatBudgetStatus(budget) {
|
|
77
|
+
const used = budget.systemPromptTokens + budget.conversationTokens + budget.fileContextTokens;
|
|
78
|
+
return (`~${used.toLocaleString()} input tokens / ${budget.contextWindow.toLocaleString()} window ` +
|
|
79
|
+
`(${budget.utilizationPct.toFixed(0)}% used)`);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=token_budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token_budget.js","sourceRoot":"","sources":["../../src/context/token_budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { TaskPriority, TaskStatus } from "./schema.js";
|
|
3
|
+
import type { DuoRole, GradingResult } from "../duo/duo_types.js";
|
|
4
|
+
export interface TaskRow {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
priority: TaskPriority;
|
|
9
|
+
required_capabilities: string;
|
|
10
|
+
status: TaskStatus;
|
|
11
|
+
worktree_path: string | null;
|
|
12
|
+
created_at: string;
|
|
13
|
+
updated_at: string;
|
|
14
|
+
}
|
|
15
|
+
export interface NegotiationSessionRow {
|
|
16
|
+
id: string;
|
|
17
|
+
task_id: string | null;
|
|
18
|
+
file_path: string;
|
|
19
|
+
language: "typescript" | "python" | "go";
|
|
20
|
+
phase: string;
|
|
21
|
+
conflict_count: number;
|
|
22
|
+
resolution_method: string | null;
|
|
23
|
+
winner_agent_id: string | null;
|
|
24
|
+
confidence: number | null;
|
|
25
|
+
explanation: string | null;
|
|
26
|
+
merged_source: string | null;
|
|
27
|
+
created_at: string;
|
|
28
|
+
updated_at: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ProviderUsageRow {
|
|
31
|
+
request_id: string;
|
|
32
|
+
task_id: string | null;
|
|
33
|
+
provider: "openai" | "anthropic" | "openrouter";
|
|
34
|
+
model: string;
|
|
35
|
+
input_tokens: number;
|
|
36
|
+
output_tokens: number;
|
|
37
|
+
cache_read_input_tokens: number;
|
|
38
|
+
cache_write_input_tokens: number;
|
|
39
|
+
cost_usd: number;
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SharedContextRow {
|
|
43
|
+
id: number;
|
|
44
|
+
task_id: string;
|
|
45
|
+
file_path: string;
|
|
46
|
+
ownership_path: string | null;
|
|
47
|
+
publisher_agent_id: string;
|
|
48
|
+
content: string;
|
|
49
|
+
visibility_csv: string;
|
|
50
|
+
created_at: string;
|
|
51
|
+
}
|
|
52
|
+
export interface NegotiationLearningRow {
|
|
53
|
+
id: number;
|
|
54
|
+
negotiation_id: string;
|
|
55
|
+
task_id: string | null;
|
|
56
|
+
file_path: string;
|
|
57
|
+
resolution_method: "auto_compose" | "debate_winner" | "escalated";
|
|
58
|
+
winner_agent_id: string | null;
|
|
59
|
+
confidence: number;
|
|
60
|
+
conflict_count: number;
|
|
61
|
+
round_count: number;
|
|
62
|
+
consensus_trend: number;
|
|
63
|
+
recommended_action: string;
|
|
64
|
+
created_at: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function getTaskById(db: Database.Database, taskId: string): TaskRow | null;
|
|
67
|
+
export declare function listTasksByStatus(db: Database.Database, status?: TaskStatus): TaskRow[];
|
|
68
|
+
export declare function getNegotiationSessionById(db: Database.Database, negotiationId: string): NegotiationSessionRow | null;
|
|
69
|
+
export declare function listNegotiationConflicts(db: Database.Database, negotiationId: string): Array<{
|
|
70
|
+
ownership_path: string;
|
|
71
|
+
left_type: string;
|
|
72
|
+
right_type: string;
|
|
73
|
+
}>;
|
|
74
|
+
export declare function listNegotiationRounds(db: Database.Database, negotiationId: string): Array<{
|
|
75
|
+
round_number: number;
|
|
76
|
+
left_score: number;
|
|
77
|
+
right_score: number;
|
|
78
|
+
consensus: number;
|
|
79
|
+
reasoning: string;
|
|
80
|
+
}>;
|
|
81
|
+
export declare function listProviderUsageByTask(db: Database.Database, taskId: string): ProviderUsageRow[];
|
|
82
|
+
export declare function getProviderSpendTotals(db: Database.Database): {
|
|
83
|
+
total_usd: number;
|
|
84
|
+
openai_usd: number;
|
|
85
|
+
anthropic_usd: number;
|
|
86
|
+
openrouter_usd: number;
|
|
87
|
+
};
|
|
88
|
+
export declare function listSharedContextByTask(db: Database.Database, taskId: string): SharedContextRow[];
|
|
89
|
+
export declare function getNegotiationLearningBySession(db: Database.Database, negotiationId: string): NegotiationLearningRow | null;
|
|
90
|
+
export declare function listNegotiationLearningByTask(db: Database.Database, taskId: string): NegotiationLearningRow[];
|
|
91
|
+
export interface EloRatingRow {
|
|
92
|
+
id: number;
|
|
93
|
+
model: string;
|
|
94
|
+
role: DuoRole;
|
|
95
|
+
capability_bucket: string;
|
|
96
|
+
elo: number;
|
|
97
|
+
match_count: number;
|
|
98
|
+
last_updated: string;
|
|
99
|
+
}
|
|
100
|
+
export declare function getEloRating(db: Database.Database, model: string, role: DuoRole, capabilityBucket: string): EloRatingRow | null;
|
|
101
|
+
export declare function upsertEloRating(db: Database.Database, model: string, role: DuoRole, capabilityBucket: string, elo: number, matchCount: number): void;
|
|
102
|
+
export declare function listEloRatingsByRole(db: Database.Database, role: DuoRole): EloRatingRow[];
|
|
103
|
+
export declare function getAggregateElo(db: Database.Database, model: string, role: DuoRole): number;
|
|
104
|
+
export interface GradingResultRow {
|
|
105
|
+
id: number;
|
|
106
|
+
task_id: string | null;
|
|
107
|
+
model: string;
|
|
108
|
+
role: DuoRole;
|
|
109
|
+
correctness: number;
|
|
110
|
+
security: number;
|
|
111
|
+
efficiency: number;
|
|
112
|
+
robustness: number;
|
|
113
|
+
maintainability: number;
|
|
114
|
+
usability: number;
|
|
115
|
+
composite_score: number;
|
|
116
|
+
graded_by: string;
|
|
117
|
+
created_at: string;
|
|
118
|
+
}
|
|
119
|
+
export declare function insertGradingResult(db: Database.Database, result: GradingResult): void;
|
|
120
|
+
export declare function listGradingResultsByModel(db: Database.Database, model: string): GradingResultRow[];
|
|
121
|
+
export declare function getAggregateMatchCount(db: Database.Database, model: string, role: DuoRole): number;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export function getTaskById(db, taskId) {
|
|
2
|
+
return db.prepare(`SELECT * FROM tasks WHERE id = ?`).get(taskId);
|
|
3
|
+
}
|
|
4
|
+
export function listTasksByStatus(db, status) {
|
|
5
|
+
if (!status) {
|
|
6
|
+
return db.prepare(`SELECT * FROM tasks ORDER BY created_at DESC`).all();
|
|
7
|
+
}
|
|
8
|
+
return db
|
|
9
|
+
.prepare(`SELECT * FROM tasks WHERE status = ? ORDER BY created_at DESC`)
|
|
10
|
+
.all(status);
|
|
11
|
+
}
|
|
12
|
+
export function getNegotiationSessionById(db, negotiationId) {
|
|
13
|
+
return db
|
|
14
|
+
.prepare(`SELECT * FROM negotiation_sessions WHERE id = ?`)
|
|
15
|
+
.get(negotiationId);
|
|
16
|
+
}
|
|
17
|
+
export function listNegotiationConflicts(db, negotiationId) {
|
|
18
|
+
return db
|
|
19
|
+
.prepare(`SELECT ownership_path, left_type, right_type FROM negotiation_conflicts WHERE negotiation_id = ? ORDER BY id ASC`)
|
|
20
|
+
.all(negotiationId);
|
|
21
|
+
}
|
|
22
|
+
export function listNegotiationRounds(db, negotiationId) {
|
|
23
|
+
return db
|
|
24
|
+
.prepare(`SELECT round_number, left_score, right_score, consensus, reasoning
|
|
25
|
+
FROM negotiation_rounds
|
|
26
|
+
WHERE negotiation_id = ?
|
|
27
|
+
ORDER BY round_number ASC`)
|
|
28
|
+
.all(negotiationId);
|
|
29
|
+
}
|
|
30
|
+
export function listProviderUsageByTask(db, taskId) {
|
|
31
|
+
return db
|
|
32
|
+
.prepare(`SELECT * FROM provider_usage WHERE task_id = ? ORDER BY created_at DESC`)
|
|
33
|
+
.all(taskId);
|
|
34
|
+
}
|
|
35
|
+
export function getProviderSpendTotals(db) {
|
|
36
|
+
return db
|
|
37
|
+
.prepare(`
|
|
38
|
+
SELECT
|
|
39
|
+
COALESCE(SUM(cost_usd), 0) AS total_usd,
|
|
40
|
+
COALESCE(SUM(CASE WHEN provider = 'openai' THEN cost_usd ELSE 0 END), 0) AS openai_usd,
|
|
41
|
+
COALESCE(SUM(CASE WHEN provider = 'anthropic' THEN cost_usd ELSE 0 END), 0) AS anthropic_usd,
|
|
42
|
+
COALESCE(SUM(CASE WHEN provider = 'openrouter' THEN cost_usd ELSE 0 END), 0) AS openrouter_usd
|
|
43
|
+
FROM provider_usage
|
|
44
|
+
`)
|
|
45
|
+
.get();
|
|
46
|
+
}
|
|
47
|
+
export function listSharedContextByTask(db, taskId) {
|
|
48
|
+
return db
|
|
49
|
+
.prepare(`SELECT * FROM shared_context WHERE task_id = ? ORDER BY created_at ASC`)
|
|
50
|
+
.all(taskId);
|
|
51
|
+
}
|
|
52
|
+
export function getNegotiationLearningBySession(db, negotiationId) {
|
|
53
|
+
return db
|
|
54
|
+
.prepare(`SELECT * FROM negotiation_learning WHERE negotiation_id = ?`)
|
|
55
|
+
.get(negotiationId);
|
|
56
|
+
}
|
|
57
|
+
export function listNegotiationLearningByTask(db, taskId) {
|
|
58
|
+
return db
|
|
59
|
+
.prepare(`SELECT * FROM negotiation_learning WHERE task_id = ? ORDER BY created_at DESC`)
|
|
60
|
+
.all(taskId);
|
|
61
|
+
}
|
|
62
|
+
export function getEloRating(db, model, role, capabilityBucket) {
|
|
63
|
+
return db
|
|
64
|
+
.prepare(`SELECT * FROM elo_ratings WHERE model = ? AND role = ? AND capability_bucket = ?`)
|
|
65
|
+
.get(model, role, capabilityBucket);
|
|
66
|
+
}
|
|
67
|
+
export function upsertEloRating(db, model, role, capabilityBucket, elo, matchCount) {
|
|
68
|
+
db.prepare(`
|
|
69
|
+
INSERT INTO elo_ratings (model, role, capability_bucket, elo, match_count, last_updated)
|
|
70
|
+
VALUES (?, ?, ?, ?, ?, datetime('now'))
|
|
71
|
+
ON CONFLICT(model, role, capability_bucket) DO UPDATE SET
|
|
72
|
+
elo = excluded.elo,
|
|
73
|
+
match_count = excluded.match_count,
|
|
74
|
+
last_updated = datetime('now')
|
|
75
|
+
`).run(model, role, capabilityBucket, elo, matchCount);
|
|
76
|
+
}
|
|
77
|
+
export function listEloRatingsByRole(db, role) {
|
|
78
|
+
return db
|
|
79
|
+
.prepare(`SELECT * FROM elo_ratings WHERE role = ? ORDER BY elo DESC`)
|
|
80
|
+
.all(role);
|
|
81
|
+
}
|
|
82
|
+
export function getAggregateElo(db, model, role) {
|
|
83
|
+
const row = db
|
|
84
|
+
.prepare(`SELECT AVG(elo) as avg_elo FROM elo_ratings WHERE model = ? AND role = ?`)
|
|
85
|
+
.get(model, role);
|
|
86
|
+
return row?.avg_elo ?? 1500;
|
|
87
|
+
}
|
|
88
|
+
export function insertGradingResult(db, result) {
|
|
89
|
+
const dims = Object.fromEntries(result.dimensions.map((d) => [d.dimension, d.score]));
|
|
90
|
+
db.prepare(`
|
|
91
|
+
INSERT INTO grading_results (
|
|
92
|
+
task_id, model, role,
|
|
93
|
+
correctness, security, efficiency, robustness, maintainability, usability,
|
|
94
|
+
composite_score, graded_by
|
|
95
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
96
|
+
`).run(result.taskId ?? null, result.model, result.role, dims.correctness ?? 0, dims.security ?? 0, dims.efficiency ?? 0, dims.robustness ?? 0, dims.maintainability ?? 0, dims.usability ?? 0, result.compositeScore, result.gradedBy);
|
|
97
|
+
}
|
|
98
|
+
export function listGradingResultsByModel(db, model) {
|
|
99
|
+
return db
|
|
100
|
+
.prepare(`SELECT * FROM grading_results WHERE model = ? ORDER BY created_at DESC`)
|
|
101
|
+
.all(model);
|
|
102
|
+
}
|
|
103
|
+
export function getAggregateMatchCount(db, model, role) {
|
|
104
|
+
const row = db
|
|
105
|
+
.prepare(`SELECT COALESCE(SUM(match_count), 0) as total FROM elo_ratings WHERE model = ? AND role = ?`)
|
|
106
|
+
.get(model, role);
|
|
107
|
+
return row?.total ?? 0;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
|