opencode-hashline 1.1.1 → 1.1.2
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/{chunk-JOA7B5LK.js → chunk-MKNRMMMR.js} +1 -1
- package/dist/{chunk-DDXOFWTU.js → chunk-X4NVISKE.js} +29 -14
- package/dist/{hashline-GY4XM34F.js → hashline-6YDKBNND.js} +3 -1
- package/dist/opencode-hashline.cjs +29 -14
- package/dist/opencode-hashline.js +3 -3
- package/dist/utils.cjs +28 -14
- package/dist/utils.js +2 -2
- package/package.json +1 -1
|
@@ -88,7 +88,8 @@ function computeLineHash(idx, line, hashLen = 3) {
|
|
|
88
88
|
return hash.toString(16).padStart(hashLen, "0");
|
|
89
89
|
}
|
|
90
90
|
function formatFileWithHashes(content, hashLen, prefix) {
|
|
91
|
-
const
|
|
91
|
+
const normalized = content.includes("\r\n") ? content.replace(/\r\n/g, "\n") : content;
|
|
92
|
+
const lines = normalized.split("\n");
|
|
92
93
|
const effectiveLen = hashLen && hashLen >= 3 ? hashLen : getAdaptiveHashLength(lines.length);
|
|
93
94
|
const effectivePrefix = prefix === void 0 ? DEFAULT_PREFIX : prefix === false ? "" : prefix;
|
|
94
95
|
const hashes = new Array(lines.length);
|
|
@@ -116,7 +117,9 @@ function stripHashes(content, prefix) {
|
|
|
116
117
|
hashLinePattern = new RegExp(`^([+ \\-])?${escapedPrefix}\\d+:[0-9a-f]{2,8}\\|`);
|
|
117
118
|
stripRegexCache.set(escapedPrefix, hashLinePattern);
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
+
const lineEnding = detectLineEnding(content);
|
|
121
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
122
|
+
const result = normalized.split("\n").map((line) => {
|
|
120
123
|
const match = line.match(hashLinePattern);
|
|
121
124
|
if (match) {
|
|
122
125
|
const patchMarker = match[1] || "";
|
|
@@ -124,6 +127,7 @@ function stripHashes(content, prefix) {
|
|
|
124
127
|
}
|
|
125
128
|
return line;
|
|
126
129
|
}).join("\n");
|
|
130
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
127
131
|
}
|
|
128
132
|
function parseHashRef(ref) {
|
|
129
133
|
const match = ref.match(/^(\d+):([0-9a-f]{2,8})$/);
|
|
@@ -189,12 +193,14 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
189
193
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
190
194
|
);
|
|
191
195
|
}
|
|
192
|
-
const
|
|
193
|
-
const
|
|
196
|
+
const lineEnding = detectLineEnding(content);
|
|
197
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
198
|
+
const lines = normalized.split("\n");
|
|
199
|
+
const startVerify = verifyHash(start.line, start.hash, normalized, hashLen, lines);
|
|
194
200
|
if (!startVerify.valid) {
|
|
195
201
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
196
202
|
}
|
|
197
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
203
|
+
const endVerify = verifyHash(end.line, end.hash, normalized, hashLen, lines);
|
|
198
204
|
if (!endVerify.valid) {
|
|
199
205
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
200
206
|
}
|
|
@@ -203,22 +209,27 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
203
209
|
startLine: start.line,
|
|
204
210
|
endLine: end.line,
|
|
205
211
|
lines: rangeLines,
|
|
206
|
-
content: rangeLines.join(
|
|
212
|
+
content: rangeLines.join(lineEnding)
|
|
207
213
|
};
|
|
208
214
|
}
|
|
209
215
|
function replaceRange(startRef, endRef, content, replacement, hashLen) {
|
|
210
|
-
const
|
|
211
|
-
const
|
|
216
|
+
const lineEnding = detectLineEnding(content);
|
|
217
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
218
|
+
const range = resolveRange(startRef, endRef, normalized, hashLen);
|
|
219
|
+
const lines = normalized.split("\n");
|
|
212
220
|
const before = lines.slice(0, range.startLine - 1);
|
|
213
221
|
const after = lines.slice(range.endLine);
|
|
214
222
|
const replacementLines = replacement.split("\n");
|
|
215
|
-
|
|
223
|
+
const result = [...before, ...replacementLines, ...after].join("\n");
|
|
224
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
216
225
|
}
|
|
217
226
|
function applyHashEdit(input, content, hashLen) {
|
|
227
|
+
const lineEnding = detectLineEnding(content);
|
|
228
|
+
const workContent = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
218
229
|
const normalizedStart = normalizeHashRef(input.startRef);
|
|
219
230
|
const start = parseHashRef(normalizedStart);
|
|
220
|
-
const lines =
|
|
221
|
-
const startVerify = verifyHash(start.line, start.hash,
|
|
231
|
+
const lines = workContent.split("\n");
|
|
232
|
+
const startVerify = verifyHash(start.line, start.hash, workContent, hashLen, lines);
|
|
222
233
|
if (!startVerify.valid) {
|
|
223
234
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
224
235
|
}
|
|
@@ -237,7 +248,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
237
248
|
operation: input.operation,
|
|
238
249
|
startLine: start.line,
|
|
239
250
|
endLine: start.line,
|
|
240
|
-
content: next2
|
|
251
|
+
content: lineEnding === "\r\n" ? next2.replace(/\n/g, "\r\n") : next2
|
|
241
252
|
};
|
|
242
253
|
}
|
|
243
254
|
const normalizedEnd = normalizeHashRef(input.endRef ?? input.startRef);
|
|
@@ -247,7 +258,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
247
258
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
248
259
|
);
|
|
249
260
|
}
|
|
250
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
261
|
+
const endVerify = verifyHash(end.line, end.hash, workContent, hashLen, lines);
|
|
251
262
|
if (!endVerify.valid) {
|
|
252
263
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
253
264
|
}
|
|
@@ -263,7 +274,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
263
274
|
operation: input.operation,
|
|
264
275
|
startLine: start.line,
|
|
265
276
|
endLine: end.line,
|
|
266
|
-
content: next
|
|
277
|
+
content: lineEnding === "\r\n" ? next.replace(/\n/g, "\r\n") : next
|
|
267
278
|
};
|
|
268
279
|
}
|
|
269
280
|
var HashlineCache = class {
|
|
@@ -338,6 +349,9 @@ var textEncoder = new TextEncoder();
|
|
|
338
349
|
function getByteLength(content) {
|
|
339
350
|
return textEncoder.encode(content).length;
|
|
340
351
|
}
|
|
352
|
+
function detectLineEnding(content) {
|
|
353
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
354
|
+
}
|
|
341
355
|
function createHashline(config) {
|
|
342
356
|
const resolved = resolveConfig(config);
|
|
343
357
|
const cache = new HashlineCache(resolved.cacheSize);
|
|
@@ -410,5 +424,6 @@ export {
|
|
|
410
424
|
matchesGlob,
|
|
411
425
|
shouldExclude,
|
|
412
426
|
getByteLength,
|
|
427
|
+
detectLineEnding,
|
|
413
428
|
createHashline
|
|
414
429
|
};
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
buildHashMap,
|
|
8
8
|
computeLineHash,
|
|
9
9
|
createHashline,
|
|
10
|
+
detectLineEnding,
|
|
10
11
|
formatFileWithHashes,
|
|
11
12
|
getAdaptiveHashLength,
|
|
12
13
|
getByteLength,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
shouldExclude,
|
|
20
21
|
stripHashes,
|
|
21
22
|
verifyHash
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-X4NVISKE.js";
|
|
23
24
|
export {
|
|
24
25
|
DEFAULT_CONFIG,
|
|
25
26
|
DEFAULT_EXCLUDE_PATTERNS,
|
|
@@ -29,6 +30,7 @@ export {
|
|
|
29
30
|
buildHashMap,
|
|
30
31
|
computeLineHash,
|
|
31
32
|
createHashline,
|
|
33
|
+
detectLineEnding,
|
|
32
34
|
formatFileWithHashes,
|
|
33
35
|
getAdaptiveHashLength,
|
|
34
36
|
getByteLength,
|
|
@@ -41,6 +41,7 @@ __export(hashline_exports, {
|
|
|
41
41
|
buildHashMap: () => buildHashMap,
|
|
42
42
|
computeLineHash: () => computeLineHash,
|
|
43
43
|
createHashline: () => createHashline,
|
|
44
|
+
detectLineEnding: () => detectLineEnding,
|
|
44
45
|
formatFileWithHashes: () => formatFileWithHashes,
|
|
45
46
|
getAdaptiveHashLength: () => getAdaptiveHashLength,
|
|
46
47
|
getByteLength: () => getByteLength,
|
|
@@ -100,7 +101,8 @@ function computeLineHash(idx, line, hashLen = 3) {
|
|
|
100
101
|
return hash.toString(16).padStart(hashLen, "0");
|
|
101
102
|
}
|
|
102
103
|
function formatFileWithHashes(content, hashLen, prefix) {
|
|
103
|
-
const
|
|
104
|
+
const normalized = content.includes("\r\n") ? content.replace(/\r\n/g, "\n") : content;
|
|
105
|
+
const lines = normalized.split("\n");
|
|
104
106
|
const effectiveLen = hashLen && hashLen >= 3 ? hashLen : getAdaptiveHashLength(lines.length);
|
|
105
107
|
const effectivePrefix = prefix === void 0 ? DEFAULT_PREFIX : prefix === false ? "" : prefix;
|
|
106
108
|
const hashes = new Array(lines.length);
|
|
@@ -127,7 +129,9 @@ function stripHashes(content, prefix) {
|
|
|
127
129
|
hashLinePattern = new RegExp(`^([+ \\-])?${escapedPrefix}\\d+:[0-9a-f]{2,8}\\|`);
|
|
128
130
|
stripRegexCache.set(escapedPrefix, hashLinePattern);
|
|
129
131
|
}
|
|
130
|
-
|
|
132
|
+
const lineEnding = detectLineEnding(content);
|
|
133
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
134
|
+
const result = normalized.split("\n").map((line) => {
|
|
131
135
|
const match = line.match(hashLinePattern);
|
|
132
136
|
if (match) {
|
|
133
137
|
const patchMarker = match[1] || "";
|
|
@@ -135,6 +139,7 @@ function stripHashes(content, prefix) {
|
|
|
135
139
|
}
|
|
136
140
|
return line;
|
|
137
141
|
}).join("\n");
|
|
142
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
138
143
|
}
|
|
139
144
|
function parseHashRef(ref) {
|
|
140
145
|
const match = ref.match(/^(\d+):([0-9a-f]{2,8})$/);
|
|
@@ -200,12 +205,14 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
200
205
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
201
206
|
);
|
|
202
207
|
}
|
|
203
|
-
const
|
|
204
|
-
const
|
|
208
|
+
const lineEnding = detectLineEnding(content);
|
|
209
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
210
|
+
const lines = normalized.split("\n");
|
|
211
|
+
const startVerify = verifyHash(start.line, start.hash, normalized, hashLen, lines);
|
|
205
212
|
if (!startVerify.valid) {
|
|
206
213
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
207
214
|
}
|
|
208
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
215
|
+
const endVerify = verifyHash(end.line, end.hash, normalized, hashLen, lines);
|
|
209
216
|
if (!endVerify.valid) {
|
|
210
217
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
211
218
|
}
|
|
@@ -214,22 +221,27 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
214
221
|
startLine: start.line,
|
|
215
222
|
endLine: end.line,
|
|
216
223
|
lines: rangeLines,
|
|
217
|
-
content: rangeLines.join(
|
|
224
|
+
content: rangeLines.join(lineEnding)
|
|
218
225
|
};
|
|
219
226
|
}
|
|
220
227
|
function replaceRange(startRef, endRef, content, replacement, hashLen) {
|
|
221
|
-
const
|
|
222
|
-
const
|
|
228
|
+
const lineEnding = detectLineEnding(content);
|
|
229
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
230
|
+
const range = resolveRange(startRef, endRef, normalized, hashLen);
|
|
231
|
+
const lines = normalized.split("\n");
|
|
223
232
|
const before = lines.slice(0, range.startLine - 1);
|
|
224
233
|
const after = lines.slice(range.endLine);
|
|
225
234
|
const replacementLines = replacement.split("\n");
|
|
226
|
-
|
|
235
|
+
const result = [...before, ...replacementLines, ...after].join("\n");
|
|
236
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
227
237
|
}
|
|
228
238
|
function applyHashEdit(input, content, hashLen) {
|
|
239
|
+
const lineEnding = detectLineEnding(content);
|
|
240
|
+
const workContent = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
229
241
|
const normalizedStart = normalizeHashRef(input.startRef);
|
|
230
242
|
const start = parseHashRef(normalizedStart);
|
|
231
|
-
const lines =
|
|
232
|
-
const startVerify = verifyHash(start.line, start.hash,
|
|
243
|
+
const lines = workContent.split("\n");
|
|
244
|
+
const startVerify = verifyHash(start.line, start.hash, workContent, hashLen, lines);
|
|
233
245
|
if (!startVerify.valid) {
|
|
234
246
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
235
247
|
}
|
|
@@ -248,7 +260,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
248
260
|
operation: input.operation,
|
|
249
261
|
startLine: start.line,
|
|
250
262
|
endLine: start.line,
|
|
251
|
-
content: next2
|
|
263
|
+
content: lineEnding === "\r\n" ? next2.replace(/\n/g, "\r\n") : next2
|
|
252
264
|
};
|
|
253
265
|
}
|
|
254
266
|
const normalizedEnd = normalizeHashRef(input.endRef ?? input.startRef);
|
|
@@ -258,7 +270,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
258
270
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
259
271
|
);
|
|
260
272
|
}
|
|
261
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
273
|
+
const endVerify = verifyHash(end.line, end.hash, workContent, hashLen, lines);
|
|
262
274
|
if (!endVerify.valid) {
|
|
263
275
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
264
276
|
}
|
|
@@ -274,7 +286,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
274
286
|
operation: input.operation,
|
|
275
287
|
startLine: start.line,
|
|
276
288
|
endLine: end.line,
|
|
277
|
-
content: next
|
|
289
|
+
content: lineEnding === "\r\n" ? next.replace(/\n/g, "\r\n") : next
|
|
278
290
|
};
|
|
279
291
|
}
|
|
280
292
|
function matchesGlob(filePath, pattern) {
|
|
@@ -289,6 +301,9 @@ function shouldExclude(filePath, patterns) {
|
|
|
289
301
|
function getByteLength(content) {
|
|
290
302
|
return textEncoder.encode(content).length;
|
|
291
303
|
}
|
|
304
|
+
function detectLineEnding(content) {
|
|
305
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
306
|
+
}
|
|
292
307
|
function createHashline(config) {
|
|
293
308
|
const resolved = resolveConfig(config);
|
|
294
309
|
const cache = new HashlineCache(resolved.cacheSize);
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
createFileReadAfterHook,
|
|
4
4
|
createSystemPromptHook,
|
|
5
5
|
setDebug
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-MKNRMMMR.js";
|
|
7
7
|
import {
|
|
8
8
|
HashlineCache,
|
|
9
9
|
applyHashEdit,
|
|
10
10
|
resolveConfig
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-X4NVISKE.js";
|
|
12
12
|
|
|
13
13
|
// src/index.ts
|
|
14
14
|
import { readFileSync as readFileSync2, realpathSync as realpathSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -172,7 +172,7 @@ function createHashlinePlugin(userConfig) {
|
|
|
172
172
|
const out = output;
|
|
173
173
|
const hashLen = config.hashLength || 0;
|
|
174
174
|
const prefix = config.prefix;
|
|
175
|
-
const { formatFileWithHashes, shouldExclude, getByteLength } = await import("./hashline-
|
|
175
|
+
const { formatFileWithHashes, shouldExclude, getByteLength } = await import("./hashline-6YDKBNND.js");
|
|
176
176
|
for (const p of out.parts ?? []) {
|
|
177
177
|
if (p.type !== "file") continue;
|
|
178
178
|
if (!p.url || !p.mime?.startsWith("text/")) continue;
|
package/dist/utils.cjs
CHANGED
|
@@ -147,7 +147,8 @@ function computeLineHash(idx, line, hashLen = 3) {
|
|
|
147
147
|
return hash.toString(16).padStart(hashLen, "0");
|
|
148
148
|
}
|
|
149
149
|
function formatFileWithHashes(content, hashLen, prefix) {
|
|
150
|
-
const
|
|
150
|
+
const normalized = content.includes("\r\n") ? content.replace(/\r\n/g, "\n") : content;
|
|
151
|
+
const lines = normalized.split("\n");
|
|
151
152
|
const effectiveLen = hashLen && hashLen >= 3 ? hashLen : getAdaptiveHashLength(lines.length);
|
|
152
153
|
const effectivePrefix = prefix === void 0 ? DEFAULT_PREFIX : prefix === false ? "" : prefix;
|
|
153
154
|
const hashes = new Array(lines.length);
|
|
@@ -175,7 +176,9 @@ function stripHashes(content, prefix) {
|
|
|
175
176
|
hashLinePattern = new RegExp(`^([+ \\-])?${escapedPrefix}\\d+:[0-9a-f]{2,8}\\|`);
|
|
176
177
|
stripRegexCache.set(escapedPrefix, hashLinePattern);
|
|
177
178
|
}
|
|
178
|
-
|
|
179
|
+
const lineEnding = detectLineEnding(content);
|
|
180
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
181
|
+
const result = normalized.split("\n").map((line) => {
|
|
179
182
|
const match = line.match(hashLinePattern);
|
|
180
183
|
if (match) {
|
|
181
184
|
const patchMarker = match[1] || "";
|
|
@@ -183,6 +186,7 @@ function stripHashes(content, prefix) {
|
|
|
183
186
|
}
|
|
184
187
|
return line;
|
|
185
188
|
}).join("\n");
|
|
189
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
186
190
|
}
|
|
187
191
|
function parseHashRef(ref) {
|
|
188
192
|
const match = ref.match(/^(\d+):([0-9a-f]{2,8})$/);
|
|
@@ -248,12 +252,14 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
248
252
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
249
253
|
);
|
|
250
254
|
}
|
|
251
|
-
const
|
|
252
|
-
const
|
|
255
|
+
const lineEnding = detectLineEnding(content);
|
|
256
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
257
|
+
const lines = normalized.split("\n");
|
|
258
|
+
const startVerify = verifyHash(start.line, start.hash, normalized, hashLen, lines);
|
|
253
259
|
if (!startVerify.valid) {
|
|
254
260
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
255
261
|
}
|
|
256
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
262
|
+
const endVerify = verifyHash(end.line, end.hash, normalized, hashLen, lines);
|
|
257
263
|
if (!endVerify.valid) {
|
|
258
264
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
259
265
|
}
|
|
@@ -262,22 +268,27 @@ function resolveRange(startRef, endRef, content, hashLen) {
|
|
|
262
268
|
startLine: start.line,
|
|
263
269
|
endLine: end.line,
|
|
264
270
|
lines: rangeLines,
|
|
265
|
-
content: rangeLines.join(
|
|
271
|
+
content: rangeLines.join(lineEnding)
|
|
266
272
|
};
|
|
267
273
|
}
|
|
268
274
|
function replaceRange(startRef, endRef, content, replacement, hashLen) {
|
|
269
|
-
const
|
|
270
|
-
const
|
|
275
|
+
const lineEnding = detectLineEnding(content);
|
|
276
|
+
const normalized = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
277
|
+
const range = resolveRange(startRef, endRef, normalized, hashLen);
|
|
278
|
+
const lines = normalized.split("\n");
|
|
271
279
|
const before = lines.slice(0, range.startLine - 1);
|
|
272
280
|
const after = lines.slice(range.endLine);
|
|
273
281
|
const replacementLines = replacement.split("\n");
|
|
274
|
-
|
|
282
|
+
const result = [...before, ...replacementLines, ...after].join("\n");
|
|
283
|
+
return lineEnding === "\r\n" ? result.replace(/\n/g, "\r\n") : result;
|
|
275
284
|
}
|
|
276
285
|
function applyHashEdit(input, content, hashLen) {
|
|
286
|
+
const lineEnding = detectLineEnding(content);
|
|
287
|
+
const workContent = lineEnding === "\r\n" ? content.replace(/\r\n/g, "\n") : content;
|
|
277
288
|
const normalizedStart = normalizeHashRef(input.startRef);
|
|
278
289
|
const start = parseHashRef(normalizedStart);
|
|
279
|
-
const lines =
|
|
280
|
-
const startVerify = verifyHash(start.line, start.hash,
|
|
290
|
+
const lines = workContent.split("\n");
|
|
291
|
+
const startVerify = verifyHash(start.line, start.hash, workContent, hashLen, lines);
|
|
281
292
|
if (!startVerify.valid) {
|
|
282
293
|
throw new Error(`Start reference invalid: ${startVerify.message}`);
|
|
283
294
|
}
|
|
@@ -296,7 +307,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
296
307
|
operation: input.operation,
|
|
297
308
|
startLine: start.line,
|
|
298
309
|
endLine: start.line,
|
|
299
|
-
content: next2
|
|
310
|
+
content: lineEnding === "\r\n" ? next2.replace(/\n/g, "\r\n") : next2
|
|
300
311
|
};
|
|
301
312
|
}
|
|
302
313
|
const normalizedEnd = normalizeHashRef(input.endRef ?? input.startRef);
|
|
@@ -306,7 +317,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
306
317
|
`Invalid range: start line ${start.line} is after end line ${end.line}`
|
|
307
318
|
);
|
|
308
319
|
}
|
|
309
|
-
const endVerify = verifyHash(end.line, end.hash,
|
|
320
|
+
const endVerify = verifyHash(end.line, end.hash, workContent, hashLen, lines);
|
|
310
321
|
if (!endVerify.valid) {
|
|
311
322
|
throw new Error(`End reference invalid: ${endVerify.message}`);
|
|
312
323
|
}
|
|
@@ -322,7 +333,7 @@ function applyHashEdit(input, content, hashLen) {
|
|
|
322
333
|
operation: input.operation,
|
|
323
334
|
startLine: start.line,
|
|
324
335
|
endLine: end.line,
|
|
325
|
-
content: next
|
|
336
|
+
content: lineEnding === "\r\n" ? next.replace(/\n/g, "\r\n") : next
|
|
326
337
|
};
|
|
327
338
|
}
|
|
328
339
|
var HashlineCache = class {
|
|
@@ -397,6 +408,9 @@ var textEncoder = new TextEncoder();
|
|
|
397
408
|
function getByteLength(content) {
|
|
398
409
|
return textEncoder.encode(content).length;
|
|
399
410
|
}
|
|
411
|
+
function detectLineEnding(content) {
|
|
412
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
413
|
+
}
|
|
400
414
|
function createHashline(config) {
|
|
401
415
|
const resolved = resolveConfig(config);
|
|
402
416
|
const cache = new HashlineCache(resolved.cacheSize);
|
package/dist/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createFileReadAfterHook,
|
|
4
4
|
createSystemPromptHook,
|
|
5
5
|
isFileReadTool
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-MKNRMMMR.js";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_CONFIG,
|
|
9
9
|
DEFAULT_EXCLUDE_PATTERNS,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
shouldExclude,
|
|
26
26
|
stripHashes,
|
|
27
27
|
verifyHash
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-X4NVISKE.js";
|
|
29
29
|
export {
|
|
30
30
|
DEFAULT_CONFIG,
|
|
31
31
|
DEFAULT_EXCLUDE_PATTERNS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-hashline",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Hashline plugin for OpenCode — content-addressable line hashing for precise AI code editing",
|
|
5
5
|
"main": "dist/opencode-hashline.cjs",
|
|
6
6
|
"module": "dist/opencode-hashline.js",
|