@theokit/sdk-tools 0.12.0 → 0.13.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/dist/index.cjs +110 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +109 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -265,6 +265,90 @@ function createSessionArtifactStore(options) {
|
|
|
265
265
|
}
|
|
266
266
|
return { write, read, has, list, path };
|
|
267
267
|
}
|
|
268
|
+
|
|
269
|
+
// src/internal/context-match.ts
|
|
270
|
+
var ContextMatchError = class extends Error {
|
|
271
|
+
reason;
|
|
272
|
+
constructor(reason, message) {
|
|
273
|
+
super(message);
|
|
274
|
+
this.name = "ContextMatchError";
|
|
275
|
+
this.reason = reason;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
function normalizeUnicode(s) {
|
|
279
|
+
return s.replace(/[‐-―−]/g, "-").replace(/[‘-‛]/g, "'").replace(/[“-‟]/g, '"').replace(/[ - ]/g, " ");
|
|
280
|
+
}
|
|
281
|
+
var LINE_MATCH_LADDER = [
|
|
282
|
+
(s) => s,
|
|
283
|
+
// exact
|
|
284
|
+
(s) => s.replace(/\s+$/, ""),
|
|
285
|
+
// rstrip (ignore trailing whitespace)
|
|
286
|
+
(s) => s.trim(),
|
|
287
|
+
// trim (ignore leading + trailing)
|
|
288
|
+
(s) => normalizeUnicode(s).trim()
|
|
289
|
+
// unicode + trim (loosest)
|
|
290
|
+
];
|
|
291
|
+
function matchesAt(lines, pattern, i, norm) {
|
|
292
|
+
for (let p = 0; p < pattern.length; p++) {
|
|
293
|
+
const lineAt = lines[i + p];
|
|
294
|
+
const patAt = pattern[p];
|
|
295
|
+
if (lineAt === void 0 || patAt === void 0 || norm(lineAt) !== norm(patAt)) return false;
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
function findHits(lines, pattern, norm) {
|
|
300
|
+
const hits = [];
|
|
301
|
+
for (let i = 0; i + pattern.length <= lines.length; i++) {
|
|
302
|
+
if (matchesAt(lines, pattern, i, norm)) hits.push(i);
|
|
303
|
+
}
|
|
304
|
+
return hits;
|
|
305
|
+
}
|
|
306
|
+
function seekUniqueLineMatch(lines, pattern, find) {
|
|
307
|
+
if (pattern.length === 0 || pattern.length > lines.length) return null;
|
|
308
|
+
for (const norm of LINE_MATCH_LADDER) {
|
|
309
|
+
const hits = findHits(lines, pattern, norm);
|
|
310
|
+
if (hits.length === 1) return hits[0] ?? null;
|
|
311
|
+
if (hits.length > 1) {
|
|
312
|
+
throw new ContextMatchError(
|
|
313
|
+
"ambiguous",
|
|
314
|
+
`target text is ambiguous (multiple matches); include more context:
|
|
315
|
+
${find}`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
function replaceUnique(content, find, replace) {
|
|
322
|
+
if (find === "") {
|
|
323
|
+
throw new ContextMatchError(
|
|
324
|
+
"empty",
|
|
325
|
+
"empty find is not a valid target; provide the text to replace"
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
const first = content.indexOf(find);
|
|
329
|
+
if (first !== -1) {
|
|
330
|
+
if (content.indexOf(find, first + 1) !== -1) {
|
|
331
|
+
throw new ContextMatchError(
|
|
332
|
+
"ambiguous",
|
|
333
|
+
`target text is ambiguous (multiple matches); include more context:
|
|
334
|
+
${find}`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return content.slice(0, first) + replace + content.slice(first + find.length);
|
|
338
|
+
}
|
|
339
|
+
const lines = content.split("\n");
|
|
340
|
+
const at = seekUniqueLineMatch(lines, find.split("\n"), find);
|
|
341
|
+
if (at === null) {
|
|
342
|
+
throw new ContextMatchError("not_found", `target text not found:
|
|
343
|
+
${find}`);
|
|
344
|
+
}
|
|
345
|
+
const patternLen = find.split("\n").length;
|
|
346
|
+
const matchedCrlf = patternLen > 0 && lines.slice(at, at + patternLen).every((l) => l.endsWith("\r"));
|
|
347
|
+
const replaceLines = matchedCrlf ? replace.split("\n").map((l) => l.endsWith("\r") ? l : `${l}\r`) : replace.split("\n");
|
|
348
|
+
return [...lines.slice(0, at), ...replaceLines, ...lines.slice(at + patternLen)].join("\n");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/edit-file.ts
|
|
268
352
|
function createEditFileTool(opts) {
|
|
269
353
|
const { projectRoot } = opts;
|
|
270
354
|
return sdk.Tool.create({
|
|
@@ -306,26 +390,36 @@ function createEditFileTool(opts) {
|
|
|
306
390
|
const exactIdx = content.indexOf(old_string);
|
|
307
391
|
if (exactIdx !== -1) {
|
|
308
392
|
await promises.copyFile(absolutePath, `${absolutePath}.bak`);
|
|
309
|
-
const
|
|
310
|
-
await promises.writeFile(absolutePath,
|
|
393
|
+
const result = content.slice(0, exactIdx) + new_string + content.slice(exactIdx + old_string.length);
|
|
394
|
+
await promises.writeFile(absolutePath, result, "utf-8");
|
|
311
395
|
return JSON.stringify({ ok: true, replacements: 1 });
|
|
312
396
|
}
|
|
313
397
|
const normalizedContent = normalizeWhitespace(content);
|
|
314
398
|
const normalizedOld = normalizeWhitespace(old_string);
|
|
315
399
|
const normalizedIdx = normalizedContent.indexOf(normalizedOld);
|
|
316
|
-
if (normalizedIdx
|
|
317
|
-
|
|
400
|
+
if (normalizedIdx !== -1) {
|
|
401
|
+
const span = findOriginalSpan(
|
|
402
|
+
content,
|
|
403
|
+
normalizedContent,
|
|
404
|
+
normalizedIdx,
|
|
405
|
+
normalizedOld.length
|
|
406
|
+
);
|
|
407
|
+
await promises.copyFile(absolutePath, `${absolutePath}.bak`);
|
|
408
|
+
const result = content.slice(0, span.start) + new_string + content.slice(span.end);
|
|
409
|
+
await promises.writeFile(absolutePath, result, "utf-8");
|
|
410
|
+
return JSON.stringify({ ok: true, replacements: 1 });
|
|
411
|
+
}
|
|
412
|
+
try {
|
|
413
|
+
const result = replaceUnique(content, old_string, new_string);
|
|
414
|
+
await promises.copyFile(absolutePath, `${absolutePath}.bak`);
|
|
415
|
+
await promises.writeFile(absolutePath, result, "utf-8");
|
|
416
|
+
return JSON.stringify({ ok: true, replacements: 1 });
|
|
417
|
+
} catch (err) {
|
|
418
|
+
if (err instanceof ContextMatchError) {
|
|
419
|
+
return JSON.stringify({ ok: false, error: "no_match", path });
|
|
420
|
+
}
|
|
421
|
+
throw err;
|
|
318
422
|
}
|
|
319
|
-
const span = findOriginalSpan(
|
|
320
|
-
content,
|
|
321
|
-
normalizedContent,
|
|
322
|
-
normalizedIdx,
|
|
323
|
-
normalizedOld.length
|
|
324
|
-
);
|
|
325
|
-
await promises.copyFile(absolutePath, `${absolutePath}.bak`);
|
|
326
|
-
const result = content.slice(0, span.start) + new_string + content.slice(span.end);
|
|
327
|
-
await promises.writeFile(absolutePath, result, "utf-8");
|
|
328
|
-
return JSON.stringify({ ok: true, replacements: 1 });
|
|
329
423
|
}
|
|
330
424
|
});
|
|
331
425
|
}
|
|
@@ -2250,6 +2344,7 @@ async function isBinaryFile(absolutePath) {
|
|
|
2250
2344
|
}
|
|
2251
2345
|
|
|
2252
2346
|
exports.CatastrophicCommandError = CatastrophicCommandError;
|
|
2347
|
+
exports.ContextMatchError = ContextMatchError;
|
|
2253
2348
|
exports.DEFAULT_TOOL_GUIDANCE = DEFAULT_TOOL_GUIDANCE;
|
|
2254
2349
|
exports.ReadTracker = ReadTracker;
|
|
2255
2350
|
exports.ReasoningTools = ReasoningTools;
|
|
@@ -2286,6 +2381,7 @@ exports.injectGuidance = injectGuidance;
|
|
|
2286
2381
|
exports.isBlockedIp = isBlockedIp;
|
|
2287
2382
|
exports.isCommandAllowed = isCommandAllowed;
|
|
2288
2383
|
exports.renderToolList = renderToolList;
|
|
2384
|
+
exports.replaceUnique = replaceUnique;
|
|
2289
2385
|
exports.resolveAndScreen = resolveAndScreen;
|
|
2290
2386
|
exports.screenedFetch = screenedFetch;
|
|
2291
2387
|
exports.todoItemsToPlanNodes = todoItemsToPlanNodes;
|