pi-hashline-edit-pro 0.15.2 → 0.15.4
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 +1 -1
- package/src/replace-diff.ts +25 -18
- package/src/replace-flat.ts +2 -1
- package/src/replace-response.ts +43 -42
- package/src/replace.ts +5 -4
package/package.json
CHANGED
package/src/replace-diff.ts
CHANGED
|
@@ -45,10 +45,19 @@ export function genDiff(
|
|
|
45
45
|
newContent: string,
|
|
46
46
|
contextLines = 2,
|
|
47
47
|
newContentHashes?: string[],
|
|
48
|
+
oldHashes?: string[],
|
|
48
49
|
): { diff: string; firstChangedLine: number | undefined } {
|
|
50
|
+
// Run Diff.diffLines on raw content only (no hash annotations) so that
|
|
51
|
+
// lines whose content is identical are never reported as changed even
|
|
52
|
+
// when their hash differs due to collision resolution or position
|
|
53
|
+
// tracking. Hashes are used purely for display via fmtDiffLine.
|
|
54
|
+
const oldLines = oldContent.split("\n");
|
|
55
|
+
const newLines = newContent.split("\n");
|
|
56
|
+
const effectiveOldHashes = oldHashes ?? _lineHashesPure(oldContent);
|
|
57
|
+
const effectiveNewHashes = newContentHashes ?? _lineHashesPure(newContent);
|
|
58
|
+
|
|
49
59
|
const parts = Diff.diffLines(oldContent, newContent);
|
|
50
60
|
const output: string[] = [];
|
|
51
|
-
const effectiveNewHashes = newContentHashes ?? _lineHashesPure(newContent);
|
|
52
61
|
let oldLineNum = 1;
|
|
53
62
|
let newLineNum = 1;
|
|
54
63
|
let lastWasChange = false;
|
|
@@ -58,18 +67,17 @@ export function genDiff(
|
|
|
58
67
|
const part = parts[i]!;
|
|
59
68
|
const raw = part.value.split("\n");
|
|
60
69
|
if (raw[raw.length - 1] === "") raw.pop();
|
|
70
|
+
const displayLines = raw;
|
|
61
71
|
|
|
62
72
|
if (part.added || part.removed) {
|
|
63
73
|
if (firstChangedLine === undefined) firstChangedLine = newLineNum;
|
|
64
|
-
for (
|
|
74
|
+
for (let k = 0; k < displayLines.length; k++) {
|
|
65
75
|
if (part.added) {
|
|
66
76
|
const hash = effectiveNewHashes[newLineNum - 1];
|
|
67
|
-
output.push(fmtDiffLine("+",
|
|
77
|
+
output.push(fmtDiffLine("+", displayLines[k]!, hash));
|
|
68
78
|
newLineNum++;
|
|
69
79
|
} else {
|
|
70
|
-
output.push(
|
|
71
|
-
fmtDiffLine("-", line, undefined),
|
|
72
|
-
);
|
|
80
|
+
output.push(fmtDiffLine("-", displayLines[k]!, undefined));
|
|
73
81
|
oldLineNum++;
|
|
74
82
|
}
|
|
75
83
|
}
|
|
@@ -80,44 +88,43 @@ export function genDiff(
|
|
|
80
88
|
const nextPartIsChange =
|
|
81
89
|
i < parts.length - 1 && (parts[i + 1]!.added || parts[i + 1]!.removed);
|
|
82
90
|
if (lastWasChange || nextPartIsChange) {
|
|
83
|
-
let linesToShow =
|
|
91
|
+
let linesToShow = displayLines;
|
|
84
92
|
let skipStart = 0;
|
|
85
93
|
let skipEnd = 0;
|
|
86
94
|
let skipMiddle = 0;
|
|
87
95
|
|
|
88
96
|
if (!lastWasChange) {
|
|
89
|
-
skipStart = Math.max(0,
|
|
90
|
-
linesToShow =
|
|
91
|
-
} else if (nextPartIsChange &&
|
|
92
|
-
const tail =
|
|
93
|
-
linesToShow = [...
|
|
94
|
-
skipMiddle =
|
|
97
|
+
skipStart = Math.max(0, displayLines.length - contextLines);
|
|
98
|
+
linesToShow = displayLines.slice(skipStart);
|
|
99
|
+
} else if (nextPartIsChange && displayLines.length > contextLines * 2) {
|
|
100
|
+
const tail = displayLines.slice(-contextLines);
|
|
101
|
+
linesToShow = [...displayLines.slice(0, contextLines), "__ELLIPSIS__", ...tail];
|
|
102
|
+
skipMiddle = displayLines.length - contextLines * 2;
|
|
95
103
|
} else if (linesToShow.length > contextLines) {
|
|
96
104
|
skipEnd = linesToShow.length - contextLines;
|
|
97
105
|
linesToShow = linesToShow.slice(0, contextLines);
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
if (skipStart > 0) {
|
|
101
|
-
output.push(
|
|
109
|
+
output.push(" ...");
|
|
102
110
|
oldLineNum += skipStart;
|
|
103
111
|
newLineNum += skipStart;
|
|
104
112
|
}
|
|
105
113
|
for (const line of linesToShow) {
|
|
106
114
|
if (line === "__ELLIPSIS__") {
|
|
107
|
-
output.push(
|
|
115
|
+
output.push(" ...");
|
|
108
116
|
oldLineNum += skipMiddle;
|
|
109
117
|
newLineNum += skipMiddle;
|
|
110
118
|
continue;
|
|
111
119
|
}
|
|
112
120
|
const hash = effectiveNewHashes[newLineNum - 1];
|
|
113
121
|
output.push(fmtDiffLine(" ", line, hash));
|
|
114
|
-
|
|
115
122
|
oldLineNum++;
|
|
116
123
|
newLineNum++;
|
|
117
124
|
}
|
|
118
125
|
} else {
|
|
119
|
-
oldLineNum +=
|
|
120
|
-
newLineNum +=
|
|
126
|
+
oldLineNum += displayLines.length;
|
|
127
|
+
newLineNum += displayLines.length;
|
|
121
128
|
}
|
|
122
129
|
lastWasChange = false;
|
|
123
130
|
}
|
package/src/replace-flat.ts
CHANGED
|
@@ -238,6 +238,7 @@ export function buildToolDef(): ToolDef {
|
|
|
238
238
|
|
|
239
239
|
const {
|
|
240
240
|
originalNormalized,
|
|
241
|
+
originalHashes,
|
|
241
242
|
result,
|
|
242
243
|
bom,
|
|
243
244
|
originalEnding,
|
|
@@ -294,13 +295,13 @@ export function buildToolDef(): ToolDef {
|
|
|
294
295
|
const successInput = {
|
|
295
296
|
path,
|
|
296
297
|
originalNormalized,
|
|
298
|
+
originalHashes,
|
|
297
299
|
result,
|
|
298
300
|
resultHashes,
|
|
299
301
|
warnings,
|
|
300
302
|
snapshotId: updatedSnapshotId,
|
|
301
303
|
editMeta,
|
|
302
304
|
};
|
|
303
|
-
|
|
304
305
|
return buildChanged(successInput);
|
|
305
306
|
});
|
|
306
307
|
},
|
package/src/replace-response.ts
CHANGED
|
@@ -40,13 +40,14 @@ export interface NoopInput {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export interface SuccessInput {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
path: string;
|
|
44
|
+
originalNormalized: string;
|
|
45
|
+
originalHashes: string[];
|
|
46
|
+
result: string;
|
|
47
|
+
resultHashes: string[];
|
|
48
|
+
warnings: string[] | undefined;
|
|
49
|
+
snapshotId: string;
|
|
50
|
+
editMeta: RMeta;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
function cntDiff(diff: string, marker: "+" | "-"): number {
|
|
@@ -139,39 +140,39 @@ export function buildNoop(input: NoopInput): TResult {
|
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
export function buildChanged(input: SuccessInput): TResult {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
143
|
+
const { path, result, warnings, snapshotId, originalNormalized, originalHashes, editMeta, resultHashes } = input;
|
|
144
|
+
|
|
145
|
+
const resultLines = visLines(result);
|
|
146
|
+
const diffResult = genDiff(originalNormalized, result, 2, resultHashes, originalHashes);
|
|
147
|
+
const addedLines = cntDiff(diffResult.diff, "+");
|
|
148
|
+
const removedLines = cntDiff(diffResult.diff, "-");
|
|
149
|
+
const warningsBlock = warnBlock(warnings);
|
|
150
|
+
const successPrefix = `Successfully replaced in ${path}.`;
|
|
151
|
+
const text = resultLines.length === 0
|
|
152
|
+
? "File is empty. Use replace to insert content."
|
|
153
|
+
: warningsBlock
|
|
154
|
+
? `${successPrefix}${warningsBlock}`
|
|
155
|
+
: successPrefix;
|
|
156
|
+
|
|
157
|
+
const metrics = buildM({
|
|
158
|
+
classification: "applied",
|
|
159
|
+
editsAttempted: editMeta.editsAttempted,
|
|
160
|
+
noopEditsCount: editMeta.noopEditsCount,
|
|
161
|
+
warningsCount: warnings?.length ?? 0,
|
|
162
|
+
firstChangedLine: editMeta.firstChangedLine,
|
|
163
|
+
lastChangedLine: editMeta.lastChangedLine,
|
|
164
|
+
addedLines,
|
|
165
|
+
removedLines,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: "text", text }],
|
|
170
|
+
details: {
|
|
171
|
+
diff: diffResult.diff,
|
|
172
|
+
firstChangedLine:
|
|
173
|
+
editMeta.firstChangedLine ?? diffResult.firstChangedLine,
|
|
174
|
+
snapshotId,
|
|
175
|
+
metrics,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
177
178
|
}
|
package/src/replace.ts
CHANGED
|
@@ -101,7 +101,7 @@ interface PipelineResult {
|
|
|
101
101
|
noopEdits?: { editIndex: number; loc: string; currentContent: string }[];
|
|
102
102
|
firstChangedLine?: number;
|
|
103
103
|
lastChangedLine?: number;
|
|
104
|
-
originalHashes
|
|
104
|
+
originalHashes: string[];
|
|
105
105
|
resultHashes: string[];
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -228,7 +228,7 @@ export async function compPreview(
|
|
|
228
228
|
try {
|
|
229
229
|
const normalized = normReq(request);
|
|
230
230
|
assertReq(normalized);
|
|
231
|
-
const { path, originalNormalized, result, resultHashes } = await execPipeline(
|
|
231
|
+
const { path, originalNormalized, originalHashes, result, resultHashes } = await execPipeline(
|
|
232
232
|
normalized,
|
|
233
233
|
cwd,
|
|
234
234
|
constants.R_OK,
|
|
@@ -240,7 +240,7 @@ export async function compPreview(
|
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
return { diff: genDiff(originalNormalized, result, 4, resultHashes).diff };
|
|
243
|
+
return { diff: genDiff(originalNormalized, result, 4, resultHashes, originalHashes).diff };
|
|
244
244
|
} catch (error: unknown) {
|
|
245
245
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
246
246
|
}
|
|
@@ -391,6 +391,7 @@ export function buildToolDef(): ToolDef {
|
|
|
391
391
|
|
|
392
392
|
const {
|
|
393
393
|
originalNormalized,
|
|
394
|
+
originalHashes,
|
|
394
395
|
result,
|
|
395
396
|
bom,
|
|
396
397
|
originalEnding,
|
|
@@ -449,13 +450,13 @@ export function buildToolDef(): ToolDef {
|
|
|
449
450
|
const successInput = {
|
|
450
451
|
path,
|
|
451
452
|
originalNormalized,
|
|
453
|
+
originalHashes,
|
|
452
454
|
result,
|
|
453
455
|
resultHashes,
|
|
454
456
|
warnings,
|
|
455
457
|
snapshotId: updatedSnapshotId,
|
|
456
458
|
editMeta,
|
|
457
459
|
};
|
|
458
|
-
|
|
459
460
|
return buildChanged(successInput);
|
|
460
461
|
});
|
|
461
462
|
},
|