ampcode-connector 0.1.5 → 0.1.6
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/package.json +5 -3
- package/src/auth/store.ts +1 -0
- package/src/index.ts +0 -0
- package/src/tools/web-read.ts +42 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ampcode-connector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Proxy AmpCode through local OAuth subscriptions (Claude Code, Codex, Gemini CLI, Antigravity)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
"dev": "bun run --watch src/index.ts",
|
|
35
35
|
"setup": "bun run src/index.ts setup",
|
|
36
36
|
"login": "bun run src/index.ts login",
|
|
37
|
-
"test": "bun test",
|
|
38
|
-
"
|
|
37
|
+
"test": "bun test tests/router.test.ts tests/middleware.test.ts tests/rewriter.test.ts",
|
|
38
|
+
"test:e2e": "bun test tests/code-assist.test.ts",
|
|
39
|
+
"check": "biome check src/ tests/ && tsc --noEmit && bun run test",
|
|
39
40
|
"format": "biome check --write src/ tests/"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@google/genai": "^1.41.0",
|
|
50
51
|
"@kreuzberg/html-to-markdown": "^2.25.0",
|
|
52
|
+
"ampcode-connector": "^0.1.5",
|
|
51
53
|
"exa-js": "^2.4.0"
|
|
52
54
|
}
|
|
53
55
|
}
|
package/src/auth/store.ts
CHANGED
|
@@ -54,6 +54,7 @@ function init() {
|
|
|
54
54
|
mkdirSync(DIR, { recursive: true, mode: 0o700 });
|
|
55
55
|
_db = new Database(DB_PATH, { strict: true });
|
|
56
56
|
_db.exec("PRAGMA journal_mode=WAL");
|
|
57
|
+
_db.exec("PRAGMA busy_timeout=5000");
|
|
57
58
|
_db.exec(`
|
|
58
59
|
CREATE TABLE IF NOT EXISTS credentials (
|
|
59
60
|
provider TEXT NOT NULL,
|
package/src/index.ts
CHANGED
|
File without changes
|
package/src/tools/web-read.ts
CHANGED
|
@@ -44,6 +44,9 @@ const RANKING = {
|
|
|
44
44
|
MIN_KEYWORD_LEN: 3,
|
|
45
45
|
HEADING_BOOST: 2,
|
|
46
46
|
BIGRAM_BOOST: 1.5,
|
|
47
|
+
POSITION_DECAY: 0.1,
|
|
48
|
+
BM25_K1: 1.5,
|
|
49
|
+
BM25_B: 0.75,
|
|
47
50
|
} as const;
|
|
48
51
|
|
|
49
52
|
const CLIPPING = {
|
|
@@ -155,20 +158,20 @@ function convertToMarkdown(raw: string, contentType: string): string {
|
|
|
155
158
|
function rankExcerpts(markdown: string, objective: string): string[] {
|
|
156
159
|
const sections = splitSections(markdown);
|
|
157
160
|
if (!sections.length) return [clipText(markdown)];
|
|
158
|
-
|
|
159
161
|
const { unigrams, bigrams } = parseTerms(objective);
|
|
160
162
|
if (!unigrams.length) return [clipText(markdown)];
|
|
161
|
-
|
|
162
|
-
const idfWeights = computeIdf(sections,
|
|
163
|
-
const
|
|
164
|
-
|
|
163
|
+
const unigramPatterns = unigrams.map((w) => new RegExp(`\\b${RegExp.escape(w)}\\b`, "g"));
|
|
164
|
+
const idfWeights = computeIdf(sections, unigramPatterns);
|
|
165
|
+
const avgDocLen = sections.reduce((sum, s) => sum + (s.text.split(/\s+/).length || 1), 0) / sections.length;
|
|
166
|
+
const totalSections = sections.length;
|
|
167
|
+
const scored = sections.map((section) =>
|
|
168
|
+
scoreSection(section, unigramPatterns, bigrams, idfWeights, avgDocLen, totalSections),
|
|
169
|
+
);
|
|
165
170
|
const hits = scored.filter((s) => s.score > 0);
|
|
166
171
|
if (!hits.length) return [clipText(markdown)];
|
|
167
|
-
|
|
168
172
|
hits.sort((a, b) => b.score - a.score || a.index - b.index);
|
|
169
173
|
const top = hits.slice(0, RANKING.MAX_SECTIONS);
|
|
170
174
|
top.sort((a, b) => a.index - b.index);
|
|
171
|
-
|
|
172
175
|
return clipMany(top.map((s) => s.text));
|
|
173
176
|
}
|
|
174
177
|
|
|
@@ -185,45 +188,61 @@ function parseTerms(objective: string): { unigrams: string[]; bigrams: RegExp[]
|
|
|
185
188
|
return { unigrams: words, bigrams };
|
|
186
189
|
}
|
|
187
190
|
|
|
188
|
-
function computeIdf(sections: Section[],
|
|
191
|
+
function computeIdf(sections: Section[], patterns: RegExp[]): number[] {
|
|
189
192
|
const lowerTexts = sections.map((section) => section.text.toLowerCase());
|
|
190
193
|
const totalSections = sections.length;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
return patterns.map((pattern) => {
|
|
195
|
+
const docFreq = lowerTexts.filter((text) => {
|
|
196
|
+
pattern.lastIndex = 0;
|
|
197
|
+
return pattern.test(text);
|
|
198
|
+
}).length;
|
|
199
|
+
return docFreq > 0 ? Math.log((totalSections - docFreq + 0.5) / (docFreq + 0.5) + 1) : 0;
|
|
196
200
|
});
|
|
197
201
|
}
|
|
198
202
|
|
|
199
|
-
function scoreSection(
|
|
203
|
+
function scoreSection(
|
|
204
|
+
section: Section,
|
|
205
|
+
unigramPatterns: RegExp[],
|
|
206
|
+
bigrams: RegExp[],
|
|
207
|
+
idfWeights: number[],
|
|
208
|
+
avgDocLen: number,
|
|
209
|
+
totalSections: number,
|
|
210
|
+
): ScoredSection {
|
|
200
211
|
const lowerText = section.text.toLowerCase();
|
|
201
212
|
const lowerHeading = section.heading.toLowerCase();
|
|
202
|
-
const
|
|
213
|
+
const docLen = lowerText.split(/\s+/).length || 1;
|
|
203
214
|
|
|
204
|
-
//
|
|
215
|
+
// BM25 scoring
|
|
216
|
+
const { BM25_K1: k1, BM25_B: b } = RANKING;
|
|
205
217
|
let score = 0;
|
|
206
|
-
for (let i = 0; i <
|
|
207
|
-
const pattern =
|
|
218
|
+
for (let i = 0; i < unigramPatterns.length; i++) {
|
|
219
|
+
const pattern = unigramPatterns[i]!;
|
|
220
|
+
pattern.lastIndex = 0;
|
|
208
221
|
const matches = lowerText.match(pattern);
|
|
209
222
|
if (matches) {
|
|
210
|
-
|
|
223
|
+
const tf = matches.length;
|
|
224
|
+
score += idfWeights[i]! * ((tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (docLen / avgDocLen))));
|
|
211
225
|
}
|
|
212
226
|
}
|
|
213
|
-
|
|
214
227
|
// Bigram bonus
|
|
215
228
|
for (const pattern of bigrams) {
|
|
216
229
|
if (pattern.test(lowerText)) score *= RANKING.BIGRAM_BOOST;
|
|
217
230
|
}
|
|
218
231
|
|
|
219
|
-
// Heading match boost
|
|
232
|
+
// Heading match boost (reuse pre-compiled patterns)
|
|
220
233
|
if (section.heading) {
|
|
221
|
-
|
|
222
|
-
|
|
234
|
+
if (
|
|
235
|
+
unigramPatterns.some((pattern) => {
|
|
236
|
+
pattern.lastIndex = 0;
|
|
237
|
+
return pattern.test(lowerHeading);
|
|
238
|
+
})
|
|
239
|
+
) {
|
|
223
240
|
score *= RANKING.HEADING_BOOST;
|
|
224
241
|
}
|
|
225
242
|
}
|
|
226
243
|
|
|
244
|
+
// Position decay — earlier sections get mild boost
|
|
245
|
+
score *= 1 + RANKING.POSITION_DECAY * (1 - section.index / totalSections);
|
|
227
246
|
return { text: section.text, score, index: section.index };
|
|
228
247
|
}
|
|
229
248
|
|