@osovv/vv-opencode 1.2.6 → 1.2.8
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 +16 -0
- package/README.md +29 -2
- package/dist/commands/patch-provider.js +2 -0
- package/dist/commands/patch-provider.js.map +1 -1
- package/dist/commands/plugin-list.js +8 -3
- package/dist/commands/plugin-list.js.map +1 -1
- package/dist/commands/plugin-toggle.js +8 -1
- package/dist/commands/plugin-toggle.js.map +1 -1
- package/dist/lib/plugin-toggle-config.d.ts +5 -1
- package/dist/lib/plugin-toggle-config.js +15 -10
- package/dist/lib/plugin-toggle-config.js.map +1 -1
- package/dist/lib/vvoc-config.d.ts +33 -1
- package/dist/lib/vvoc-config.js +49 -1
- package/dist/lib/vvoc-config.js.map +1 -1
- package/dist/plugins/hashline-edit/diff-summary.d.ts +7 -0
- package/dist/plugins/hashline-edit/diff-summary.js +79 -0
- package/dist/plugins/hashline-edit/diff-summary.js.map +1 -0
- package/dist/plugins/hashline-edit/edit-operation-primitives.d.ts +2 -2
- package/dist/plugins/hashline-edit/edit-operation-primitives.js +56 -37
- package/dist/plugins/hashline-edit/edit-operation-primitives.js.map +1 -1
- package/dist/plugins/hashline-edit/edit-operations.d.ts +1 -0
- package/dist/plugins/hashline-edit/edit-operations.js +17 -10
- package/dist/plugins/hashline-edit/edit-operations.js.map +1 -1
- package/dist/plugins/hashline-edit/edit-text-normalization.d.ts +27 -4
- package/dist/plugins/hashline-edit/edit-text-normalization.js +45 -56
- package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -1
- package/dist/plugins/hashline-edit/index.js +331 -35
- package/dist/plugins/hashline-edit/index.js.map +1 -1
- package/dist/plugins/hashline-edit/normalize-edits.js +56 -20
- package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -1
- package/dist/plugins/hashline-edit/replace-engine.d.ts +24 -0
- package/dist/plugins/hashline-edit/replace-engine.js +246 -0
- package/dist/plugins/hashline-edit/replace-engine.js.map +1 -0
- package/dist/plugins/hashline-edit/routing.d.ts +21 -0
- package/dist/plugins/hashline-edit/routing.js +113 -0
- package/dist/plugins/hashline-edit/routing.js.map +1 -0
- package/dist/plugins/hashline-edit/session-state.d.ts +23 -0
- package/dist/plugins/hashline-edit/session-state.js +70 -0
- package/dist/plugins/hashline-edit/session-state.js.map +1 -0
- package/dist/plugins/hashline-edit/str-replace-editor.d.ts +50 -0
- package/dist/plugins/hashline-edit/str-replace-editor.js +285 -0
- package/dist/plugins/hashline-edit/str-replace-editor.js.map +1 -0
- package/dist/plugins/hashline-edit/tool-description.d.ts +2 -1
- package/dist/plugins/hashline-edit/tool-description.js +44 -18
- package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
- package/dist/plugins/hashline-edit/validation.d.ts +1 -0
- package/dist/plugins/hashline-edit/validation.js +13 -3
- package/dist/plugins/hashline-edit/validation.js.map +1 -1
- package/package.json +1 -1
- package/schemas/vvoc/v3.json +29 -2
- package/dist/plugins/hashline-edit/autocorrect-replacement-lines.d.ts +0 -1
- package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js +0 -188
- package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// FILE: src/plugins/hashline-edit/normalize-edits.ts
|
|
2
|
-
// VERSION: 0.
|
|
2
|
+
// VERSION: 0.5.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Validate and normalize raw hashline tool arguments into strongly-typed edit operations.
|
|
5
|
-
// SCOPE: Raw edit input shape, anchor trimming, required-field validation, and replace
|
|
6
|
-
// DEPENDS: [src/plugins/hashline-edit/types.ts]
|
|
5
|
+
// SCOPE: Raw edit input shape, anchor trimming, three-part anchor enforcement, required-field validation, physical single-line payload enforcement, blank-payload rejection for replacements, and unified replace (optional end) with replace_range alias plus append/prepend normalization.
|
|
6
|
+
// DEPENDS: [src/plugins/hashline-edit/types.ts, src/plugins/hashline-edit/validation.ts]
|
|
7
7
|
// LINKS: [M-PLUGIN-HASHLINE-EDIT]
|
|
8
8
|
// ROLE: RUNTIME
|
|
9
9
|
// MAP_MODE: EXPORTS
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
// END_MODULE_MAP
|
|
16
16
|
//
|
|
17
17
|
// START_CHANGE_SUMMARY
|
|
18
|
-
// LAST_CHANGE: [v0.
|
|
18
|
+
// LAST_CHANGE: [v0.5.0 - Unified replace to accept an optional end anchor (range semantics) with replace_range kept as an alias, rejected multi-line replace without end via add-end guidance, and enforced three-part anchors on all edit references.]
|
|
19
19
|
// END_CHANGE_SUMMARY
|
|
20
|
+
import { requireThreePartRef } from "./validation.js";
|
|
20
21
|
function normalizeAnchor(value) {
|
|
21
22
|
if (typeof value !== "string") {
|
|
22
23
|
return undefined;
|
|
@@ -24,6 +25,14 @@ function normalizeAnchor(value) {
|
|
|
24
25
|
const trimmed = value.trim();
|
|
25
26
|
return trimmed === "" ? undefined : trimmed;
|
|
26
27
|
}
|
|
28
|
+
function requireAnchor(value, index, field) {
|
|
29
|
+
const anchor = normalizeAnchor(value);
|
|
30
|
+
if (anchor === undefined) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
requireThreePartRef(anchor, `Edit ${index} ${field}`);
|
|
34
|
+
return anchor;
|
|
35
|
+
}
|
|
27
36
|
function requireLines(edit, index) {
|
|
28
37
|
if (edit.lines === undefined) {
|
|
29
38
|
throw new Error(`Edit ${index}: lines is required for ${edit.op ?? "unknown"}`);
|
|
@@ -34,41 +43,47 @@ function requireLines(edit, index) {
|
|
|
34
43
|
return edit.lines;
|
|
35
44
|
}
|
|
36
45
|
function normalizeReplaceEdit(edit, index) {
|
|
37
|
-
const pos =
|
|
46
|
+
const pos = requireAnchor(edit.pos, index, "pos");
|
|
38
47
|
if (!pos) {
|
|
39
48
|
throw new Error(`Edit ${index}: replace requires pos anchor`);
|
|
40
49
|
}
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
const end = requireAnchor(edit.end, index, "end");
|
|
51
|
+
const lines = requireLines(edit, index);
|
|
52
|
+
assertNonBlankReplacement(edit, index, lines);
|
|
53
|
+
assertPhysicalLines(edit, index, lines);
|
|
54
|
+
// With an end anchor, replace applies as an inclusive range (pos..end).
|
|
55
|
+
if (end) {
|
|
56
|
+
return { op: "replace_range", pos, end, lines };
|
|
43
57
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
const lineCount = Array.isArray(lines) ? lines.length : lines.split("\n").length;
|
|
59
|
+
if (lineCount > 1) {
|
|
60
|
+
throw new Error(`Edit ${index}: replace received ${lineCount} replacement lines but no end anchor. ` +
|
|
61
|
+
"Add the end anchor of the last line to replace (pos..end is inclusive), or pass a single replacement line.");
|
|
47
62
|
}
|
|
48
|
-
return {
|
|
49
|
-
op: "replace",
|
|
50
|
-
pos,
|
|
51
|
-
lines: requireLines(edit, index),
|
|
52
|
-
};
|
|
63
|
+
return { op: "replace", pos, lines };
|
|
53
64
|
}
|
|
54
65
|
function normalizeReplaceRangeEdit(edit, index) {
|
|
55
|
-
const pos =
|
|
56
|
-
const end =
|
|
66
|
+
const pos = requireAnchor(edit.pos, index, "pos");
|
|
67
|
+
const end = requireAnchor(edit.end, index, "end");
|
|
57
68
|
if (!pos || !end) {
|
|
58
69
|
throw new Error(`Edit ${index}: replace_range requires both pos and end anchors`);
|
|
59
70
|
}
|
|
71
|
+
const lines = requireLines(edit, index);
|
|
72
|
+
assertNonBlankReplacement(edit, index, lines);
|
|
73
|
+
assertPhysicalLines(edit, index, lines);
|
|
60
74
|
return {
|
|
61
75
|
op: "replace_range",
|
|
62
76
|
pos,
|
|
63
77
|
end,
|
|
64
|
-
lines
|
|
78
|
+
lines,
|
|
65
79
|
};
|
|
66
80
|
}
|
|
67
81
|
function normalizeInsertEdit(edit, index, op) {
|
|
68
|
-
const pos =
|
|
69
|
-
const end =
|
|
82
|
+
const pos = requireAnchor(edit.pos, index, "pos");
|
|
83
|
+
const end = requireAnchor(edit.end, index, "end");
|
|
70
84
|
const anchor = pos ?? end;
|
|
71
85
|
const lines = requireLines(edit, index);
|
|
86
|
+
assertPhysicalLines(edit, index, lines);
|
|
72
87
|
const normalized = {
|
|
73
88
|
op,
|
|
74
89
|
lines,
|
|
@@ -78,6 +93,27 @@ function normalizeInsertEdit(edit, index, op) {
|
|
|
78
93
|
}
|
|
79
94
|
return normalized;
|
|
80
95
|
}
|
|
96
|
+
function assertPhysicalLines(edit, index, lines) {
|
|
97
|
+
if (typeof lines === "string") {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
for (let entryIndex = 0; entryIndex < lines.length; entryIndex += 1) {
|
|
101
|
+
const entry = lines[entryIndex] ?? "";
|
|
102
|
+
if (entry.includes("\n") || entry.includes("\r")) {
|
|
103
|
+
throw new Error(`Edit ${index}: lines[${entryIndex}] for ${edit.op ?? "unknown"} contains an embedded newline. ` +
|
|
104
|
+
"Each array entry must be exactly one physical line; split the content into separate entries.");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function assertNonBlankReplacement(edit, index, lines) {
|
|
109
|
+
const isBlank = (typeof lines === "string" && lines === "") ||
|
|
110
|
+
(Array.isArray(lines) && lines.length === 1 && lines[0] === "");
|
|
111
|
+
if (!isBlank) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Edit ${index}: ${edit.op ?? "unknown"} with a single blank line (lines: [""]) is ambiguous and was rejected. ` +
|
|
115
|
+
"To delete lines use lines: [] or lines: null. To insert a blank line use append or prepend.");
|
|
116
|
+
}
|
|
81
117
|
export function normalizeHashlineEdits(rawEdits) {
|
|
82
118
|
return rawEdits.map((rawEdit, index) => {
|
|
83
119
|
const edit = rawEdit ?? {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-edits.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/normalize-edits.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,iBAAiB;AACjB,wBAAwB;AACxB,qGAAqG;AACrG
|
|
1
|
+
{"version":3,"file":"normalize-edits.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/normalize-edits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ReplaceEditParams {
|
|
2
|
+
oldString: string;
|
|
3
|
+
newString: string;
|
|
4
|
+
replaceAll?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export type ReplaceMatchLayer = "exact" | "unicode_confusables" | "trailing_whitespace";
|
|
7
|
+
export type ReplaceApplyResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
content: string;
|
|
10
|
+
layer: ReplaceMatchLayer;
|
|
11
|
+
replacements: number;
|
|
12
|
+
warnings: string[];
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: string;
|
|
16
|
+
warnings: string[];
|
|
17
|
+
};
|
|
18
|
+
export declare function applyReplaceEdit(content: string, params: ReplaceEditParams): ReplaceApplyResult;
|
|
19
|
+
export declare function formatReplaceSuccess(filePath: string, beforeContent: string, result: {
|
|
20
|
+
content: string;
|
|
21
|
+
layer: ReplaceMatchLayer;
|
|
22
|
+
replacements: number;
|
|
23
|
+
warnings: string[];
|
|
24
|
+
}): string;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// FILE: src/plugins/hashline-edit/replace-engine.ts
|
|
2
|
+
// VERSION: 0.1.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Apply oldString/newString replace edits with the native qwen/kimi harness contract: exact literal matching, limited visible fallback layers, uniqueness rules, and teaching errors. Tool-facing snake_case aliases (old_string/new_string) are resolved to this engine at the plugin layer.
|
|
5
|
+
// SCOPE: Pure content-level replace application with exact, unicode-confusables, and trailing-whitespace layers; occurrence counting; replace-all mode; result formatting with bounded diff summary.
|
|
6
|
+
// DEPENDS: [src/plugins/hashline-edit/diff-summary.ts]
|
|
7
|
+
// LINKS: [M-PLUGIN-HASHLINE-EDIT]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// ReplaceEditParams - Tool-facing replace arguments (oldString, newString, replaceAll).
|
|
14
|
+
// ReplaceMatchLayer - Which matching layer produced the applied match.
|
|
15
|
+
// ReplaceApplyResult - Structured outcome: applied content with layer and replacement count, or a teaching error.
|
|
16
|
+
// applyReplaceEdit - Apply a replace edit to file content with layered fail-closed matching.
|
|
17
|
+
// formatReplaceSuccess - Render the success output with stats, warnings, and bounded diff.
|
|
18
|
+
// END_MODULE_MAP
|
|
19
|
+
//
|
|
20
|
+
// START_CHANGE_SUMMARY
|
|
21
|
+
// LAST_CHANGE: [v0.1.0 - Established the replace profile engine with exact, unicode-confusables, and trailing-whitespace layers adapted from the qwen-code contract (Apache-2.0).]
|
|
22
|
+
// END_CHANGE_SUMMARY
|
|
23
|
+
import { findFirstChangedLine, summarizeEditDiff } from "./diff-summary.js";
|
|
24
|
+
// END_BLOCK_TYPES
|
|
25
|
+
// START_BLOCK_CONFUSABLES
|
|
26
|
+
// Character-level typography normalization adapted from qwen-code editHelper
|
|
27
|
+
// (Apache-2.0). Every entry maps one code point to one code point so string
|
|
28
|
+
// offsets are preserved between original and normalized text.
|
|
29
|
+
const UNICODE_EQUIVALENT_MAP = {
|
|
30
|
+
"\u2010": "-",
|
|
31
|
+
"\u2011": "-",
|
|
32
|
+
"\u2012": "-",
|
|
33
|
+
"\u2013": "-",
|
|
34
|
+
"\u2014": "-",
|
|
35
|
+
"\u2015": "-",
|
|
36
|
+
"\u2212": "-",
|
|
37
|
+
"\u2018": "'",
|
|
38
|
+
"\u2019": "'",
|
|
39
|
+
"\u201A": "'",
|
|
40
|
+
"\u201B": "'",
|
|
41
|
+
"\u201C": '"',
|
|
42
|
+
"\u201D": '"',
|
|
43
|
+
"\u201E": '"',
|
|
44
|
+
"\u201F": '"',
|
|
45
|
+
"\u00A0": " ",
|
|
46
|
+
"\u2002": " ",
|
|
47
|
+
"\u2003": " ",
|
|
48
|
+
"\u2004": " ",
|
|
49
|
+
"\u2005": " ",
|
|
50
|
+
"\u2006": " ",
|
|
51
|
+
"\u2007": " ",
|
|
52
|
+
"\u2008": " ",
|
|
53
|
+
"\u2009": " ",
|
|
54
|
+
"\u200A": " ",
|
|
55
|
+
"\u202F": " ",
|
|
56
|
+
"\u205F": " ",
|
|
57
|
+
"\u3000": " ",
|
|
58
|
+
};
|
|
59
|
+
function normalizeConfusables(text) {
|
|
60
|
+
let normalized = "";
|
|
61
|
+
for (const char of text) {
|
|
62
|
+
normalized += UNICODE_EQUIVALENT_MAP[char] ?? char;
|
|
63
|
+
}
|
|
64
|
+
return normalized;
|
|
65
|
+
}
|
|
66
|
+
// END_BLOCK_CONFUSABLES
|
|
67
|
+
// START_BLOCK_MATCHING
|
|
68
|
+
function countOccurrences(content, needle) {
|
|
69
|
+
if (needle.length === 0) {
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
let count = 0;
|
|
73
|
+
let position = 0;
|
|
74
|
+
while (position < content.length) {
|
|
75
|
+
const index = content.indexOf(needle, position);
|
|
76
|
+
if (index === -1) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
count += 1;
|
|
80
|
+
position = index + needle.length;
|
|
81
|
+
}
|
|
82
|
+
return count;
|
|
83
|
+
}
|
|
84
|
+
function matchTrailingWhitespaceBlocks(content, oldString) {
|
|
85
|
+
const contentLines = content.split("\n");
|
|
86
|
+
const searchLines = oldString.split("\n").map((line) => line.trimEnd());
|
|
87
|
+
if (searchLines.every((line) => line === "")) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const offsets = [];
|
|
91
|
+
let cursor = 0;
|
|
92
|
+
for (const line of contentLines) {
|
|
93
|
+
offsets.push(cursor);
|
|
94
|
+
cursor += line.length + 1;
|
|
95
|
+
}
|
|
96
|
+
const blocks = [];
|
|
97
|
+
for (let i = 0; i + searchLines.length <= contentLines.length; i += 1) {
|
|
98
|
+
let matches = true;
|
|
99
|
+
for (let j = 0; j < searchLines.length; j += 1) {
|
|
100
|
+
if ((contentLines[i + j] ?? "").trimEnd() !== searchLines[j]) {
|
|
101
|
+
matches = false;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!matches) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const lastIndex = i + searchLines.length - 1;
|
|
109
|
+
blocks.push({
|
|
110
|
+
start: offsets[i],
|
|
111
|
+
end: offsets[lastIndex] + (contentLines[lastIndex] ?? "").length,
|
|
112
|
+
});
|
|
113
|
+
i = lastIndex;
|
|
114
|
+
}
|
|
115
|
+
return blocks;
|
|
116
|
+
}
|
|
117
|
+
function ambiguityError(count) {
|
|
118
|
+
return (`Failed to edit: oldString matches ${count} locations in the file. ` +
|
|
119
|
+
"Provide more surrounding context to make the match unique, or set replaceAll to true to replace every occurrence.");
|
|
120
|
+
}
|
|
121
|
+
function notFoundError() {
|
|
122
|
+
return ("Failed to edit: oldString not found. The exact text was not found in the file. " +
|
|
123
|
+
"Check whitespace, indentation, and context, and use the Read tool to verify the current " +
|
|
124
|
+
"content before retrying; the file may have changed since you last read it.");
|
|
125
|
+
}
|
|
126
|
+
// Offsets are identical in original and normalized text because every
|
|
127
|
+
// confusable maps one code point to one code point.
|
|
128
|
+
function replaceNormalizedOccurrences(original, normalized, normalizedNeedle, replacement, all) {
|
|
129
|
+
let result = "";
|
|
130
|
+
let cursor = 0;
|
|
131
|
+
let position = 0;
|
|
132
|
+
while (position < normalized.length) {
|
|
133
|
+
const index = normalized.indexOf(normalizedNeedle, position);
|
|
134
|
+
if (index === -1) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
result += original.slice(cursor, index) + replacement;
|
|
138
|
+
cursor = index + normalizedNeedle.length;
|
|
139
|
+
position = index + normalizedNeedle.length;
|
|
140
|
+
if (!all) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
result += original.slice(cursor);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
// END_BLOCK_MATCHING
|
|
148
|
+
// START_BLOCK_APPLY
|
|
149
|
+
export function applyReplaceEdit(content, params) {
|
|
150
|
+
const warnings = [];
|
|
151
|
+
const replaceAll = params.replaceAll ?? false;
|
|
152
|
+
if (params.oldString === params.newString) {
|
|
153
|
+
return {
|
|
154
|
+
ok: false,
|
|
155
|
+
error: "No changes to apply: oldString and newString are identical.",
|
|
156
|
+
warnings,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
if (params.oldString === "") {
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
error: "oldString cannot be empty when editing an existing file. Provide the exact text to replace.",
|
|
163
|
+
warnings,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Layer 1: exact literal match.
|
|
167
|
+
const exactCount = countOccurrences(content, params.oldString);
|
|
168
|
+
if (exactCount > 0) {
|
|
169
|
+
if (!replaceAll && exactCount > 1) {
|
|
170
|
+
return { ok: false, error: ambiguityError(exactCount), warnings };
|
|
171
|
+
}
|
|
172
|
+
const next = replaceAll
|
|
173
|
+
? content.split(params.oldString).join(params.newString)
|
|
174
|
+
: content.replace(params.oldString, params.newString);
|
|
175
|
+
return {
|
|
176
|
+
ok: true,
|
|
177
|
+
content: next,
|
|
178
|
+
layer: "exact",
|
|
179
|
+
replacements: replaceAll ? exactCount : 1,
|
|
180
|
+
warnings,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// Layer 2: unicode confusables (typography characters equated to ASCII).
|
|
184
|
+
const normalizedContent = normalizeConfusables(content);
|
|
185
|
+
const normalizedOld = normalizeConfusables(params.oldString);
|
|
186
|
+
if (normalizedContent !== content || normalizedOld !== params.oldString) {
|
|
187
|
+
const normalizedCount = countOccurrences(normalizedContent, normalizedOld);
|
|
188
|
+
if (normalizedCount > 0) {
|
|
189
|
+
if (!replaceAll && normalizedCount > 1) {
|
|
190
|
+
return { ok: false, error: ambiguityError(normalizedCount), warnings };
|
|
191
|
+
}
|
|
192
|
+
warnings.push("oldString matched after unicode confusables normalization (typography characters such as curly quotes, dashes, or special spaces were equated to ASCII); the replacement was applied to the original bytes.");
|
|
193
|
+
const next = replaceNormalizedOccurrences(content, normalizedContent, normalizedOld, params.newString, replaceAll);
|
|
194
|
+
return {
|
|
195
|
+
ok: true,
|
|
196
|
+
content: next,
|
|
197
|
+
layer: "unicode_confusables",
|
|
198
|
+
replacements: replaceAll ? normalizedCount : 1,
|
|
199
|
+
warnings,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Layer 3: trailing whitespace ignored per line; indentation stays exact.
|
|
204
|
+
const blocks = matchTrailingWhitespaceBlocks(content, params.oldString);
|
|
205
|
+
if (blocks.length > 0) {
|
|
206
|
+
if (!replaceAll && blocks.length > 1) {
|
|
207
|
+
return { ok: false, error: ambiguityError(blocks.length), warnings };
|
|
208
|
+
}
|
|
209
|
+
warnings.push(`oldString matched after ignoring trailing whitespace on ${blocks.length} block(s); leading whitespace (indentation) was matched exactly.`);
|
|
210
|
+
const selected = replaceAll ? blocks : blocks.slice(0, 1);
|
|
211
|
+
let next = content;
|
|
212
|
+
for (let i = selected.length - 1; i >= 0; i -= 1) {
|
|
213
|
+
const block = selected[i];
|
|
214
|
+
next = next.slice(0, block.start) + params.newString + next.slice(block.end);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
ok: true,
|
|
218
|
+
content: next,
|
|
219
|
+
layer: "trailing_whitespace",
|
|
220
|
+
replacements: selected.length,
|
|
221
|
+
warnings,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return { ok: false, error: notFoundError(), warnings };
|
|
225
|
+
}
|
|
226
|
+
// END_BLOCK_APPLY
|
|
227
|
+
// START_BLOCK_FORMAT
|
|
228
|
+
export function formatReplaceSuccess(filePath, beforeContent, result) {
|
|
229
|
+
const diff = summarizeEditDiff(beforeContent, result.content);
|
|
230
|
+
const firstChangedLine = findFirstChangedLine(beforeContent, result.content);
|
|
231
|
+
const stats = `+${diff.additions}/-${diff.deletions}${firstChangedLine !== undefined ? `, first change line ${firstChangedLine}` : ""}`;
|
|
232
|
+
const parts = [`Updated ${filePath} (${stats})`];
|
|
233
|
+
if (result.layer !== "exact") {
|
|
234
|
+
parts.push(`Note: matched via ${result.layer} fallback layer.`);
|
|
235
|
+
}
|
|
236
|
+
if (result.replacements > 1) {
|
|
237
|
+
parts.push(`Note: replaced ${result.replacements} occurrences.`);
|
|
238
|
+
}
|
|
239
|
+
for (const warning of result.warnings) {
|
|
240
|
+
parts.push(`Warning: ${warning}`);
|
|
241
|
+
}
|
|
242
|
+
parts.push(...diff.rendered);
|
|
243
|
+
return parts.join("\n");
|
|
244
|
+
}
|
|
245
|
+
// END_BLOCK_FORMAT
|
|
246
|
+
//# sourceMappingURL=replace-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replace-engine.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/replace-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const EDIT_MODES: readonly ["hashline", "replace", "str_replace_editor", "passthrough"];
|
|
2
|
+
export type EditMode = (typeof EDIT_MODES)[number];
|
|
3
|
+
export interface RoutingRule {
|
|
4
|
+
pattern: string;
|
|
5
|
+
mode: EditMode;
|
|
6
|
+
}
|
|
7
|
+
export interface RoutingConfig {
|
|
8
|
+
default: EditMode;
|
|
9
|
+
rules: RoutingRule[];
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_ROUTING_CONFIG: RoutingConfig;
|
|
12
|
+
export declare function parseRoutingConfig(raw: unknown): RoutingConfig;
|
|
13
|
+
export interface HashlineEditPluginSettings {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
routing: RoutingConfig;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseHashlineEditPluginEntry(raw: unknown): HashlineEditPluginSettings;
|
|
18
|
+
export declare function resolveEditMode(config: RoutingConfig, model: {
|
|
19
|
+
providerID?: string;
|
|
20
|
+
modelID?: string;
|
|
21
|
+
} | undefined): EditMode;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// FILE: src/plugins/hashline-edit/routing.ts
|
|
2
|
+
// VERSION: 0.1.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Define edit-mode routing configuration and resolve the active edit mode for a session model.
|
|
5
|
+
// SCOPE: EditMode vocabulary, strict routing config parsing with the default routing table, plugin entry union resolution, and case-insensitive provider-then-model substring matching.
|
|
6
|
+
// DEPENDS: [none]
|
|
7
|
+
// LINKS: [M-PLUGIN-HASHLINE-EDIT]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// EDIT_MODES - Canonical edit mode identifiers accepted by routing configuration.
|
|
14
|
+
// EditMode - Union type of edit mode identifiers.
|
|
15
|
+
// RoutingRule - One ordered pattern-to-mode routing entry.
|
|
16
|
+
// RoutingConfig - Parsed routing table with default mode and ordered rules.
|
|
17
|
+
// DEFAULT_ROUTING_CONFIG - Built-in routing table applied when config does not override it.
|
|
18
|
+
// parseRoutingConfig - Strictly parse an unknown routing value into a RoutingConfig or throw.
|
|
19
|
+
// HashlineEditPluginSettings - Resolved enabled flag and routing config for the hashline-edit plugin entry.
|
|
20
|
+
// parseHashlineEditPluginEntry - Resolve the plugins["hashline-edit"] boolean-or-object union into enabled flag and routing config.
|
|
21
|
+
// resolveEditMode - Resolve the active edit mode for a provider/model pair against a routing config.
|
|
22
|
+
// END_MODULE_MAP
|
|
23
|
+
//
|
|
24
|
+
// START_CHANGE_SUMMARY
|
|
25
|
+
// LAST_CHANGE: [v0.1.0 - Established routing vocabulary, default table, strict parsing, and provider-then-model resolution.]
|
|
26
|
+
// END_CHANGE_SUMMARY
|
|
27
|
+
// START_BLOCK_VOCABULARY
|
|
28
|
+
export const EDIT_MODES = ["hashline", "replace", "str_replace_editor", "passthrough"];
|
|
29
|
+
// END_BLOCK_VOCABULARY
|
|
30
|
+
// START_BLOCK_DEFAULT_TABLE
|
|
31
|
+
export const DEFAULT_ROUTING_CONFIG = {
|
|
32
|
+
default: "hashline",
|
|
33
|
+
rules: [
|
|
34
|
+
{ pattern: "deepseek", mode: "str_replace_editor" },
|
|
35
|
+
{ pattern: "kimi", mode: "replace" },
|
|
36
|
+
{ pattern: "qwen", mode: "replace" },
|
|
37
|
+
{ pattern: "gpt", mode: "passthrough" },
|
|
38
|
+
{ pattern: "codex", mode: "passthrough" },
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
// END_BLOCK_DEFAULT_TABLE
|
|
42
|
+
// START_BLOCK_PARSE
|
|
43
|
+
function isRecord(value) {
|
|
44
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
function parseEditMode(value, where) {
|
|
47
|
+
if (typeof value === "string" && EDIT_MODES.includes(value)) {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`hashline-edit routing: ${where} must be one of ${EDIT_MODES.join(", ")}; got ${JSON.stringify(value)}`);
|
|
51
|
+
}
|
|
52
|
+
export function parseRoutingConfig(raw) {
|
|
53
|
+
if (raw === undefined || raw === null) {
|
|
54
|
+
return DEFAULT_ROUTING_CONFIG;
|
|
55
|
+
}
|
|
56
|
+
if (!isRecord(raw)) {
|
|
57
|
+
throw new Error("hashline-edit routing: routing config must be an object");
|
|
58
|
+
}
|
|
59
|
+
const defaultMode = raw.default === undefined ? "hashline" : parseEditMode(raw.default, "default");
|
|
60
|
+
const rules = [];
|
|
61
|
+
if (raw.rules !== undefined) {
|
|
62
|
+
if (!isRecord(raw.rules)) {
|
|
63
|
+
throw new Error("hashline-edit routing: rules must be an object mapping patterns to modes");
|
|
64
|
+
}
|
|
65
|
+
for (const [pattern, mode] of Object.entries(raw.rules)) {
|
|
66
|
+
if (pattern.trim().length === 0) {
|
|
67
|
+
throw new Error("hashline-edit routing: rule patterns must be non-empty strings");
|
|
68
|
+
}
|
|
69
|
+
rules.push({ pattern, mode: parseEditMode(mode, `rules["${pattern}"]`) });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { default: defaultMode, rules };
|
|
73
|
+
}
|
|
74
|
+
export function parseHashlineEditPluginEntry(raw) {
|
|
75
|
+
if (raw === undefined || raw === null) {
|
|
76
|
+
return { enabled: true, routing: DEFAULT_ROUTING_CONFIG };
|
|
77
|
+
}
|
|
78
|
+
if (typeof raw === "boolean") {
|
|
79
|
+
return { enabled: raw, routing: DEFAULT_ROUTING_CONFIG };
|
|
80
|
+
}
|
|
81
|
+
if (!isRecord(raw)) {
|
|
82
|
+
throw new Error('hashline-edit: plugins["hashline-edit"] must be a boolean or an object');
|
|
83
|
+
}
|
|
84
|
+
const enabled = raw.enabled === undefined ? true : raw.enabled;
|
|
85
|
+
if (typeof enabled !== "boolean") {
|
|
86
|
+
throw new Error("hashline-edit: enabled must be a boolean");
|
|
87
|
+
}
|
|
88
|
+
return { enabled, routing: parseRoutingConfig(raw.routing) };
|
|
89
|
+
}
|
|
90
|
+
// END_BLOCK_PARSE
|
|
91
|
+
// START_BLOCK_RESOLVE
|
|
92
|
+
export function resolveEditMode(config, model) {
|
|
93
|
+
if (!model) {
|
|
94
|
+
return config.default;
|
|
95
|
+
}
|
|
96
|
+
const providerID = model.providerID?.toLowerCase();
|
|
97
|
+
const modelID = model.modelID?.toLowerCase();
|
|
98
|
+
for (const rule of config.rules) {
|
|
99
|
+
const pattern = rule.pattern.toLowerCase();
|
|
100
|
+
if (providerID !== undefined && providerID.includes(pattern)) {
|
|
101
|
+
return rule.mode;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const rule of config.rules) {
|
|
105
|
+
const pattern = rule.pattern.toLowerCase();
|
|
106
|
+
if (modelID !== undefined && modelID.includes(pattern)) {
|
|
107
|
+
return rule.mode;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return config.default;
|
|
111
|
+
}
|
|
112
|
+
// END_BLOCK_RESOLVE
|
|
113
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface SessionModelInfo {
|
|
2
|
+
providerID: string;
|
|
3
|
+
modelID: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class SessionModelCache {
|
|
6
|
+
#private;
|
|
7
|
+
set(sessionID: string, model: SessionModelInfo): void;
|
|
8
|
+
get(sessionID: string): SessionModelInfo | undefined;
|
|
9
|
+
delete(sessionID: string): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface FileSnapshot {
|
|
13
|
+
mtimeMs: number;
|
|
14
|
+
size: number;
|
|
15
|
+
}
|
|
16
|
+
export type FileCacheVerdict = "unread" | "fresh" | "drifted";
|
|
17
|
+
export declare class SessionFileCache {
|
|
18
|
+
#private;
|
|
19
|
+
record(sessionID: string, filePath: string, snapshot: FileSnapshot): void;
|
|
20
|
+
check(sessionID: string, filePath: string, current: FileSnapshot | undefined): FileCacheVerdict;
|
|
21
|
+
forget(sessionID: string, filePath: string): void;
|
|
22
|
+
clear(): void;
|
|
23
|
+
}
|