@aexol/spectral 0.9.71 → 0.9.72
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/dist/extensions/browser/browser-service.d.ts.map +1 -1
- package/dist/extensions/browser/browser-service.js +14 -0
- package/dist/sdk/coding-agent/core/tools/edit-diff.d.ts +5 -9
- package/dist/sdk/coding-agent/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/edit-diff.js +121 -34
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-service.d.ts","sourceRoot":"","sources":["../../../src/extensions/browser/browser-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser-service.d.ts","sourceRoot":"","sources":["../../../src/extensions/browser/browser-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { registerSessionResourceCleanup } from "../../sdk/ai/session-resources.js";
|
|
2
3
|
import { getBrowserConfig } from "./config.js";
|
|
3
4
|
const _require = createRequire(import.meta.url);
|
|
4
5
|
let _pw = null;
|
|
@@ -19,6 +20,7 @@ function loadPlaywright() {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
let instance = null;
|
|
23
|
+
let unregisterInstanceCleanup = null;
|
|
22
24
|
export class BrowserService {
|
|
23
25
|
browser = null;
|
|
24
26
|
context = null;
|
|
@@ -36,10 +38,22 @@ export class BrowserService {
|
|
|
36
38
|
static getInstance(config) {
|
|
37
39
|
if (!instance) {
|
|
38
40
|
instance = new BrowserService(config);
|
|
41
|
+
unregisterInstanceCleanup?.();
|
|
42
|
+
unregisterInstanceCleanup = registerSessionResourceCleanup(() => {
|
|
43
|
+
const current = instance;
|
|
44
|
+
instance = null;
|
|
45
|
+
unregisterInstanceCleanup?.();
|
|
46
|
+
unregisterInstanceCleanup = null;
|
|
47
|
+
if (!current)
|
|
48
|
+
return;
|
|
49
|
+
void current.close().catch(() => { });
|
|
50
|
+
});
|
|
39
51
|
}
|
|
40
52
|
return instance;
|
|
41
53
|
}
|
|
42
54
|
static resetInstance() {
|
|
55
|
+
unregisterInstanceCleanup?.();
|
|
56
|
+
unregisterInstanceCleanup = null;
|
|
43
57
|
instance = null;
|
|
44
58
|
}
|
|
45
59
|
static isAvailable() {
|
|
@@ -16,16 +16,13 @@ export declare function normalizeForFuzzyMatch(text: string): string;
|
|
|
16
16
|
export interface FuzzyMatchResult {
|
|
17
17
|
/** Whether a match was found */
|
|
18
18
|
found: boolean;
|
|
19
|
-
/** The index where the match starts
|
|
19
|
+
/** The index where the match starts in the original content */
|
|
20
20
|
index: number;
|
|
21
21
|
/** Length of the matched text */
|
|
22
22
|
matchLength: number;
|
|
23
23
|
/** Whether fuzzy matching was used (false = exact match) */
|
|
24
24
|
usedFuzzyMatch: boolean;
|
|
25
|
-
/**
|
|
26
|
-
* The content to use for replacement operations.
|
|
27
|
-
* When exact match: original content. When fuzzy match: normalized content.
|
|
28
|
-
*/
|
|
25
|
+
/** The original content to use for replacement operations. */
|
|
29
26
|
contentForReplacement: string;
|
|
30
27
|
}
|
|
31
28
|
export interface Edit {
|
|
@@ -37,10 +34,9 @@ export interface AppliedEditsResult {
|
|
|
37
34
|
newContent: string;
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
40
|
-
* Find oldText in content, trying exact match first, then
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* Unicode quotes/dashes normalized to ASCII).
|
|
37
|
+
* Find oldText in content, trying exact match first, then tolerant whitespace matching.
|
|
38
|
+
* Fuzzy matches still return indexes into the original content, so replacements preserve
|
|
39
|
+
* untouched text outside the matched span.
|
|
44
40
|
*/
|
|
45
41
|
export declare function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult;
|
|
46
42
|
/** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/edit-diff.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE9E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;
|
|
1
|
+
{"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/edit-diff.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE9E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAmHD,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,cAAc,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,qBAAqB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,IAAI;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AASD,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAkBhF;AAED,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEvE;AA4CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC5C,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,GACV,kBAAkB,CA4DpB;AAED,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,MAAM,CAKnH;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,YAAY,SAAI,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAuHxD;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EAAE,EACb,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAyBzC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAEzC"}
|
|
@@ -48,29 +48,124 @@ export function normalizeForFuzzyMatch(text) {
|
|
|
48
48
|
// U+205F medium math space, U+3000 ideographic space
|
|
49
49
|
.replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " "));
|
|
50
50
|
}
|
|
51
|
+
function allIndexes(content, search) {
|
|
52
|
+
const indexes = [];
|
|
53
|
+
if (search.length === 0)
|
|
54
|
+
return indexes;
|
|
55
|
+
let index = content.indexOf(search);
|
|
56
|
+
while (index !== -1) {
|
|
57
|
+
indexes.push(index);
|
|
58
|
+
index = content.indexOf(search, index + 1);
|
|
59
|
+
}
|
|
60
|
+
return indexes;
|
|
61
|
+
}
|
|
62
|
+
function isTrimmedHorizontalWhitespace(char) {
|
|
63
|
+
return /[\t\f\v \u00A0\u2002-\u200A\u202F\u205F\u3000]/u.test(char);
|
|
64
|
+
}
|
|
65
|
+
function normalizeTrimEndWithMap(text) {
|
|
66
|
+
const out = [];
|
|
67
|
+
const map = [];
|
|
68
|
+
let lineStart = 0;
|
|
69
|
+
for (let i = 0; i <= text.length; i++) {
|
|
70
|
+
if (i !== text.length && text[i] !== "\n")
|
|
71
|
+
continue;
|
|
72
|
+
let lineEnd = i;
|
|
73
|
+
while (lineEnd > lineStart && isTrimmedHorizontalWhitespace(text[lineEnd - 1])) {
|
|
74
|
+
lineEnd--;
|
|
75
|
+
}
|
|
76
|
+
for (let j = lineStart; j < lineEnd; j++) {
|
|
77
|
+
out.push(text[j]);
|
|
78
|
+
map.push(j);
|
|
79
|
+
}
|
|
80
|
+
if (i < text.length) {
|
|
81
|
+
out.push("\n");
|
|
82
|
+
map.push(i);
|
|
83
|
+
}
|
|
84
|
+
lineStart = i + 1;
|
|
85
|
+
}
|
|
86
|
+
return { text: out.join(""), map };
|
|
87
|
+
}
|
|
88
|
+
function dedupeMatches(matches) {
|
|
89
|
+
const seen = new Set();
|
|
90
|
+
return matches.filter((match) => {
|
|
91
|
+
const key = `${match.index}:${match.matchLength}`;
|
|
92
|
+
if (seen.has(key))
|
|
93
|
+
return false;
|
|
94
|
+
seen.add(key);
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function findTrimEndMatches(content, oldText) {
|
|
99
|
+
const normalizedContent = normalizeTrimEndWithMap(content);
|
|
100
|
+
const normalizedOldText = normalizeTrimEndWithMap(oldText).text;
|
|
101
|
+
return allIndexes(normalizedContent.text, normalizedOldText).map((index) => {
|
|
102
|
+
const normalizedEnd = index + normalizedOldText.length;
|
|
103
|
+
const start = normalizedContent.map[index] ?? 0;
|
|
104
|
+
const end = normalizedEnd >= normalizedContent.map.length
|
|
105
|
+
? content.length
|
|
106
|
+
: (normalizedContent.map[normalizedEnd - 1] ?? start) + 1;
|
|
107
|
+
return { index: start, matchLength: Math.max(0, end - start), usedFuzzyMatch: true };
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function getLineRanges(content) {
|
|
111
|
+
const ranges = [];
|
|
112
|
+
let start = 0;
|
|
113
|
+
for (let i = 0; i <= content.length; i++) {
|
|
114
|
+
if (i !== content.length && content[i] !== "\n")
|
|
115
|
+
continue;
|
|
116
|
+
const endWithNewline = i < content.length ? i + 1 : i;
|
|
117
|
+
ranges.push({ start, endNoNewline: i, endWithNewline, text: content.slice(start, i) });
|
|
118
|
+
start = i + 1;
|
|
119
|
+
}
|
|
120
|
+
return ranges;
|
|
121
|
+
}
|
|
122
|
+
function findTrimmedLineMatches(content, oldText) {
|
|
123
|
+
const hasTrailingNewline = oldText.endsWith("\n");
|
|
124
|
+
const oldLines = (hasTrailingNewline ? oldText.slice(0, -1) : oldText).split("\n");
|
|
125
|
+
if (oldLines.length === 0 || (oldLines.length === 1 && oldLines[0].trim().length === 0))
|
|
126
|
+
return [];
|
|
127
|
+
const normalizedOldLines = oldLines.map((line) => normalizeForFuzzyMatch(line).trim());
|
|
128
|
+
const contentLines = getLineRanges(content);
|
|
129
|
+
const matches = [];
|
|
130
|
+
for (let i = 0; i <= contentLines.length - oldLines.length; i++) {
|
|
131
|
+
let matched = true;
|
|
132
|
+
for (let j = 0; j < oldLines.length; j++) {
|
|
133
|
+
const contentLine = normalizeForFuzzyMatch(contentLines[i + j].text).trim();
|
|
134
|
+
if (contentLine !== normalizedOldLines[j]) {
|
|
135
|
+
matched = false;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!matched)
|
|
140
|
+
continue;
|
|
141
|
+
const start = contentLines[i].start;
|
|
142
|
+
const lastLine = contentLines[i + oldLines.length - 1];
|
|
143
|
+
const end = hasTrailingNewline ? lastLine.endWithNewline : lastLine.endNoNewline;
|
|
144
|
+
matches.push({ index: start, matchLength: end - start, usedFuzzyMatch: true });
|
|
145
|
+
}
|
|
146
|
+
return matches;
|
|
147
|
+
}
|
|
148
|
+
function findTextMatches(content, oldText) {
|
|
149
|
+
const exactMatches = allIndexes(content, oldText).map((index) => ({
|
|
150
|
+
index,
|
|
151
|
+
matchLength: oldText.length,
|
|
152
|
+
usedFuzzyMatch: false,
|
|
153
|
+
}));
|
|
154
|
+
if (exactMatches.length > 0)
|
|
155
|
+
return exactMatches;
|
|
156
|
+
const trimEndMatches = findTrimEndMatches(content, oldText);
|
|
157
|
+
if (trimEndMatches.length > 0)
|
|
158
|
+
return dedupeMatches(trimEndMatches);
|
|
159
|
+
return dedupeMatches(findTrimmedLineMatches(content, oldText));
|
|
160
|
+
}
|
|
51
161
|
/**
|
|
52
|
-
* Find oldText in content, trying exact match first, then
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* Unicode quotes/dashes normalized to ASCII).
|
|
162
|
+
* Find oldText in content, trying exact match first, then tolerant whitespace matching.
|
|
163
|
+
* Fuzzy matches still return indexes into the original content, so replacements preserve
|
|
164
|
+
* untouched text outside the matched span.
|
|
56
165
|
*/
|
|
57
166
|
export function fuzzyFindText(content, oldText) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (exactIndex !== -1) {
|
|
61
|
-
return {
|
|
62
|
-
found: true,
|
|
63
|
-
index: exactIndex,
|
|
64
|
-
matchLength: oldText.length,
|
|
65
|
-
usedFuzzyMatch: false,
|
|
66
|
-
contentForReplacement: content,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// Try fuzzy match - work entirely in normalized space
|
|
70
|
-
const fuzzyContent = normalizeForFuzzyMatch(content);
|
|
71
|
-
const fuzzyOldText = normalizeForFuzzyMatch(oldText);
|
|
72
|
-
const fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);
|
|
73
|
-
if (fuzzyIndex === -1) {
|
|
167
|
+
const match = findTextMatches(content, oldText)[0];
|
|
168
|
+
if (!match) {
|
|
74
169
|
return {
|
|
75
170
|
found: false,
|
|
76
171
|
index: -1,
|
|
@@ -79,15 +174,12 @@ export function fuzzyFindText(content, oldText) {
|
|
|
79
174
|
contentForReplacement: content,
|
|
80
175
|
};
|
|
81
176
|
}
|
|
82
|
-
// When fuzzy matching, we work in the normalized space for replacement.
|
|
83
|
-
// This means the output will have normalized whitespace/quotes/dashes,
|
|
84
|
-
// which is acceptable since we're fixing minor formatting differences anyway.
|
|
85
177
|
return {
|
|
86
178
|
found: true,
|
|
87
|
-
index:
|
|
88
|
-
matchLength:
|
|
89
|
-
usedFuzzyMatch:
|
|
90
|
-
contentForReplacement:
|
|
179
|
+
index: match.index,
|
|
180
|
+
matchLength: match.matchLength,
|
|
181
|
+
usedFuzzyMatch: match.usedFuzzyMatch,
|
|
182
|
+
contentForReplacement: content,
|
|
91
183
|
};
|
|
92
184
|
}
|
|
93
185
|
/** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
|
|
@@ -95,9 +187,7 @@ export function stripBom(content) {
|
|
|
95
187
|
return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
|
|
96
188
|
}
|
|
97
189
|
function countOccurrences(content, oldText) {
|
|
98
|
-
|
|
99
|
-
const fuzzyOldText = normalizeForFuzzyMatch(oldText);
|
|
100
|
-
return fuzzyContent.split(fuzzyOldText).length - 1;
|
|
190
|
+
return findTextMatches(content, oldText).length;
|
|
101
191
|
}
|
|
102
192
|
function getNotFoundError(path, editIndex, totalEdits) {
|
|
103
193
|
if (totalEdits === 1) {
|
|
@@ -141,10 +231,7 @@ export function applyEditsToNormalizedContent(normalizedContent, edits, path) {
|
|
|
141
231
|
throw getEmptyOldTextError(path, i, normalizedEdits.length);
|
|
142
232
|
}
|
|
143
233
|
}
|
|
144
|
-
const
|
|
145
|
-
const baseContent = initialMatches.some((match) => match.usedFuzzyMatch)
|
|
146
|
-
? normalizeForFuzzyMatch(normalizedContent)
|
|
147
|
-
: normalizedContent;
|
|
234
|
+
const baseContent = normalizedContent;
|
|
148
235
|
const matchedEdits = [];
|
|
149
236
|
for (let i = 0; i < normalizedEdits.length; i++) {
|
|
150
237
|
const edit = normalizedEdits[i];
|