pi-hashline-edit-pro 4.1.0 → 4.2.0
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/README.md +9 -6
- package/index.ts +20 -2
- package/package.json +1 -1
- package/prompts/insert-guidelines.md +1 -0
- package/prompts/insert.md +1 -1
- package/prompts/replace-guidelines.md +2 -1
- package/prompts/replace.md +1 -1
- package/src/anchor-registry.ts +1 -5
- package/src/batch.ts +614 -0
- package/src/commit.ts +1 -1
- package/src/config-ui.ts +19 -4
- package/src/config.ts +21 -8
- package/src/edit-common.ts +14 -12
- package/src/grep.ts +1 -1
- package/src/hashline/apply.ts +128 -84
- package/src/hashline/index.ts +3 -0
- package/src/insert.ts +59 -49
- package/src/payload-contract.ts +28 -0
- package/src/replace.ts +65 -25
package/src/replace.ts
CHANGED
|
@@ -22,7 +22,6 @@ import { applyEdit,
|
|
|
22
22
|
type HEdit,
|
|
23
23
|
type NEdit,
|
|
24
24
|
} from "./hashline";
|
|
25
|
-
import { commitEdit } from "./commit";
|
|
26
25
|
import { withDedupRows, type RMetrics } from "./replace-response";
|
|
27
26
|
import {
|
|
28
27
|
type RPreview,
|
|
@@ -33,7 +32,9 @@ import { adoptAnchors, servedForPath } from "./anchor-registry";
|
|
|
33
32
|
import { resolveTarget } from "./fs-write";
|
|
34
33
|
import { toCwd } from "./paths";
|
|
35
34
|
import { noopPayloadKey, markBoundaryNoop, consumeBoundaryBypass, clearBoundaryBypass } from "./boundary-bypass";
|
|
36
|
-
import { queuedEdit, editToolBase, editRenderCallWrapper, editRenderResultWrapper, resolveEditTargetWithRequirement, throwIfStrictInput,
|
|
35
|
+
import { queuedEdit, editToolBase, editRenderCallWrapper, editRenderResultWrapper, resolveEditTargetWithRequirement, throwIfStrictInput, getBoundaryDedupMode, withReplacePrompts, DEFAULT_EDIT_FLAGS, type EditToolFlags } from "./edit-common";
|
|
36
|
+
import { commitEdit } from "./commit";
|
|
37
|
+
import { batchMemberFor, executeBatchMember, noteBatchFailure } from "./batch";
|
|
37
38
|
|
|
38
39
|
export { editToolSchema, type ReqParams, assertReq };
|
|
39
40
|
|
|
@@ -47,6 +48,7 @@ export type ReplaceDetails = {
|
|
|
47
48
|
metrics?: RMetrics;
|
|
48
49
|
diffLineNumbers?: (number|undefined)[];
|
|
49
50
|
warnings?: string[];
|
|
51
|
+
batch?: { id: number; size: number; last: boolean; total: number };
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
export interface PipelineResult {
|
|
@@ -112,13 +114,7 @@ function countLineChanges(
|
|
|
112
114
|
};
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
export
|
|
116
|
-
targetPath: string,
|
|
117
|
-
params: ReqParams,
|
|
118
|
-
cwd: string,
|
|
119
|
-
options?: ExecPipelineOptions,
|
|
120
|
-
): Promise<PipelineResult> {
|
|
121
|
-
|
|
117
|
+
export function buildReplaceHEdit(params: ReqParams): { edit: HEdit; warnings: string[] } {
|
|
122
118
|
const editWarnings: string[] = [];
|
|
123
119
|
let replacementLines = params.replacement_lines;
|
|
124
120
|
const expandedReplacement = decodeStringArray(replacementLines);
|
|
@@ -134,7 +130,17 @@ export async function execPipeline(
|
|
|
134
130
|
},
|
|
135
131
|
editWarnings,
|
|
136
132
|
);
|
|
133
|
+
return { edit, warnings: editWarnings };
|
|
134
|
+
}
|
|
137
135
|
|
|
136
|
+
export async function execPipeline(
|
|
137
|
+
targetPath: string,
|
|
138
|
+
params: ReqParams,
|
|
139
|
+
cwd: string,
|
|
140
|
+
options?: ExecPipelineOptions,
|
|
141
|
+
): Promise<PipelineResult> {
|
|
142
|
+
|
|
143
|
+
const { edit, warnings: editWarnings } = buildReplaceHEdit(params);
|
|
138
144
|
const hashStore = options?.store ?? await loadHashStore();
|
|
139
145
|
const preResolvedPath = await resolveTarget(toCwd(targetPath, cwd));
|
|
140
146
|
const served = servedForPath(preResolvedPath);
|
|
@@ -143,8 +149,9 @@ export async function execPipeline(
|
|
|
143
149
|
);
|
|
144
150
|
const displayPath = relative(cwd, absolutePath).replace(/\\/g, "/") || targetPath;
|
|
145
151
|
|
|
146
|
-
const
|
|
147
|
-
const effectiveSkipBoundaryDedup = options?.skipBoundaryDedup === true ||
|
|
152
|
+
const dedupMode = await getBoundaryDedupMode();
|
|
153
|
+
const effectiveSkipBoundaryDedup = options?.skipBoundaryDedup === true || dedupMode === "off";
|
|
154
|
+
const strictBoundaryDedup = options?.skipBoundaryDedup !== true && dedupMode === "strict";
|
|
148
155
|
let anchorResult: ReturnType<typeof applyEdit>;
|
|
149
156
|
try {
|
|
150
157
|
anchorResult = applyEdit(
|
|
@@ -155,6 +162,7 @@ export async function execPipeline(
|
|
|
155
162
|
displayPath,
|
|
156
163
|
served,
|
|
157
164
|
effectiveSkipBoundaryDedup,
|
|
165
|
+
strictBoundaryDedup,
|
|
158
166
|
);
|
|
159
167
|
} catch (error) {
|
|
160
168
|
await noteAnchorError(absolutePath, error, originalHashes, options?.noPersist);
|
|
@@ -275,29 +283,61 @@ export function buildToolDef(flags: EditToolFlags = DEFAULT_EDIT_FLAGS): ToolDef
|
|
|
275
283
|
removeTo: normalizedParams.remove_to,
|
|
276
284
|
providedPath: normalizedParams.path,
|
|
277
285
|
cwd: ctx.cwd,
|
|
286
|
+
}).catch((error: unknown) => {
|
|
287
|
+
const member = batchMemberFor(_toolCallId);
|
|
288
|
+
if (member) noteBatchFailure(member, error);
|
|
289
|
+
throw error;
|
|
278
290
|
});
|
|
279
291
|
return queuedEdit(targetPath, ctx.cwd, signal, async (absolutePath, mutationTargetPath) => {
|
|
280
|
-
const
|
|
292
|
+
const dedupMode = await getBoundaryDedupMode();
|
|
293
|
+
const dedupOn = dedupMode !== "off";
|
|
281
294
|
const noopPayload = noopPayloadKey(mutationTargetPath, normalizedParams.remove_from, normalizedParams.remove_to, normalizedParams.replacement_lines);
|
|
282
295
|
const boundaryBypass = dedupOn ? consumeBoundaryBypass(mutationTargetPath, noopPayload) : false;
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
296
|
+
const strictBoundaryDedup = dedupMode === "strict" && !boundaryBypass;
|
|
297
|
+
const member = batchMemberFor(_toolCallId);
|
|
298
|
+
if (!member) {
|
|
299
|
+
const pipe = await execPipeline(
|
|
300
|
+
targetPath,
|
|
301
|
+
normalizedParams,
|
|
302
|
+
ctx.cwd,
|
|
303
|
+
{ accessMode: constants.R_OK | constants.W_OK, signal, skipBoundaryDedup: boundaryBypass },
|
|
304
|
+
);
|
|
305
|
+
const appliedWarnings = boundaryBypass
|
|
306
|
+
? ["[W_BOUNDARY_BYPASS] Boundary dedup was off for this call and is back on."]
|
|
307
|
+
: [];
|
|
308
|
+
return commitEdit(pipe, {
|
|
309
|
+
path: pipe.path,
|
|
310
|
+
absolutePath,
|
|
311
|
+
mutationTargetPath,
|
|
312
|
+
editAnchors: [normalizedParams.remove_from, normalizedParams.remove_to],
|
|
313
|
+
signal,
|
|
314
|
+
appliedWarnings,
|
|
315
|
+
onApplied: () => { if (dedupOn) clearBoundaryBypass(mutationTargetPath); },
|
|
316
|
+
onNoopDedup: dedupOn ? () => markBoundaryNoop(mutationTargetPath, noopPayload) : undefined,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
let built: { edit: HEdit; warnings: string[] };
|
|
320
|
+
try {
|
|
321
|
+
built = buildReplaceHEdit(normalizedParams);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
noteBatchFailure(member, error);
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
289
326
|
const appliedWarnings = boundaryBypass
|
|
290
327
|
? ["[W_BOUNDARY_BYPASS] Boundary dedup was off for this call and is back on."]
|
|
291
328
|
: [];
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
|
|
329
|
+
return executeBatchMember({
|
|
330
|
+
kind: "replace",
|
|
331
|
+
member,
|
|
332
|
+
targetPath,
|
|
295
333
|
mutationTargetPath,
|
|
296
|
-
|
|
334
|
+
cwd: ctx.cwd,
|
|
297
335
|
signal,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
336
|
+
hedit: built.edit,
|
|
337
|
+
extraWarnings: [...built.warnings, ...appliedWarnings],
|
|
338
|
+
skipBoundaryDedup: boundaryBypass,
|
|
339
|
+
strictBoundaryDedup,
|
|
340
|
+
noopPayload,
|
|
301
341
|
});
|
|
302
342
|
});
|
|
303
343
|
},
|