@ddlqhd/agent-sdk 0.1.0 → 0.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 +4 -2
- package/dist/{chunk-5QMA2YBY.cjs → chunk-6X7EYQLS.cjs} +782 -114
- package/dist/chunk-6X7EYQLS.cjs.map +1 -0
- package/dist/{chunk-NDSL7NPN.js → chunk-D3UZNLZO.js} +769 -71
- package/dist/chunk-D3UZNLZO.js.map +1 -0
- package/dist/{chunk-Q3SOMX26.js → chunk-EQ5CXH44.js} +772 -111
- package/dist/chunk-EQ5CXH44.js.map +1 -0
- package/dist/chunk-LOYIGOBZ.js +54 -0
- package/dist/chunk-LOYIGOBZ.js.map +1 -0
- package/dist/{chunk-OHXW2YM6.js → chunk-MEJHTQJM.js} +289 -166
- package/dist/chunk-MEJHTQJM.js.map +1 -0
- package/dist/chunk-NYZD3THB.cjs +1521 -0
- package/dist/chunk-NYZD3THB.cjs.map +1 -0
- package/dist/chunk-OZO7D77N.cjs +59 -0
- package/dist/chunk-OZO7D77N.cjs.map +1 -0
- package/dist/{chunk-JF5AJQMU.cjs → chunk-Z45DHTDX.cjs} +291 -170
- package/dist/chunk-Z45DHTDX.cjs.map +1 -0
- package/dist/cli/index.cjs +47 -39
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +22 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/{index-DPsZ1zat.d.ts → index-Cw3SfEAB.d.ts} +20 -34
- package/dist/{index-RTPmFjMp.d.cts → index-D2Qntkn_.d.cts} +20 -34
- package/dist/index.cjs +125 -89
- package/dist/index.d.cts +62 -22
- package/dist/index.d.ts +62 -22
- package/dist/index.js +4 -4
- package/dist/models/index.cjs +19 -15
- package/dist/models/index.d.cts +55 -6
- package/dist/models/index.d.ts +55 -6
- package/dist/models/index.js +2 -2
- package/dist/tools/index.cjs +53 -61
- package/dist/tools/index.d.cts +3 -3
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/index.js +2 -2
- package/dist/{types-C0aX_Qdp.d.cts → types-CWPAYWzr.d.cts} +307 -61
- package/dist/{types-C0aX_Qdp.d.ts → types-CWPAYWzr.d.ts} +307 -61
- package/package.json +25 -14
- package/dist/chunk-5QMA2YBY.cjs.map +0 -1
- package/dist/chunk-CNSGZVRN.cjs +0 -152
- package/dist/chunk-CNSGZVRN.cjs.map +0 -1
- package/dist/chunk-JF5AJQMU.cjs.map +0 -1
- package/dist/chunk-NDSL7NPN.js.map +0 -1
- package/dist/chunk-OHXW2YM6.js.map +0 -1
- package/dist/chunk-Q3SOMX26.js.map +0 -1
- package/dist/chunk-WH3APNQ5.js +0 -147
- package/dist/chunk-WH3APNQ5.js.map +0 -1
- package/dist/chunk-X35MHWXE.cjs +0 -817
- package/dist/chunk-X35MHWXE.cjs.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkOZO7D77N_cjs = require('./chunk-OZO7D77N.cjs');
|
|
5
5
|
var promises = require('fs/promises');
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var os = require('os');
|
|
8
|
-
var zod = require('zod');
|
|
9
8
|
var iconv = require('iconv-lite');
|
|
10
9
|
var fg = require('fast-glob');
|
|
10
|
+
var zod = require('zod');
|
|
11
11
|
var chardet = require('chardet');
|
|
12
12
|
var child_process = require('child_process');
|
|
13
13
|
var fs = require('fs');
|
|
@@ -253,16 +253,20 @@ var OutputHandler = class {
|
|
|
253
253
|
function createOutputHandler(userBasePath) {
|
|
254
254
|
return new OutputHandler(userBasePath);
|
|
255
255
|
}
|
|
256
|
+
|
|
257
|
+
// src/tools/registry.ts
|
|
256
258
|
var ToolRegistry = class {
|
|
257
259
|
tools = /* @__PURE__ */ new Map();
|
|
258
260
|
categories = /* @__PURE__ */ new Map();
|
|
259
261
|
outputHandler;
|
|
260
262
|
hookManager = null;
|
|
261
263
|
executionPolicy;
|
|
264
|
+
hookObserver;
|
|
262
265
|
constructor(config) {
|
|
263
266
|
const enableOutputHandler = config?.enableOutputHandler !== false;
|
|
264
267
|
this.outputHandler = enableOutputHandler ? createOutputHandler(config?.userBasePath) : null;
|
|
265
268
|
this.executionPolicy = config?.executionPolicy;
|
|
269
|
+
this.hookObserver = config?.hookObserver;
|
|
266
270
|
}
|
|
267
271
|
/**
|
|
268
272
|
* 工具名是否在 {@link ToolExecutionPolicy.disallowedTools} 中(无策略时为 false)。
|
|
@@ -329,6 +333,14 @@ var ToolRegistry = class {
|
|
|
329
333
|
...extra
|
|
330
334
|
};
|
|
331
335
|
}
|
|
336
|
+
hookObserverCtx(eventType, name, options) {
|
|
337
|
+
return {
|
|
338
|
+
eventType,
|
|
339
|
+
toolName: name,
|
|
340
|
+
toolCallId: options?.toolCallId,
|
|
341
|
+
projectDir: options?.projectDir
|
|
342
|
+
};
|
|
343
|
+
}
|
|
332
344
|
/**
|
|
333
345
|
* 注册工具
|
|
334
346
|
*/
|
|
@@ -399,6 +411,11 @@ var ToolRegistry = class {
|
|
|
399
411
|
}
|
|
400
412
|
const tool = this.tools.get(name);
|
|
401
413
|
if (!tool) {
|
|
414
|
+
if (hookMgr) {
|
|
415
|
+
this.hookObserver?.onHookStart?.(
|
|
416
|
+
this.hookObserverCtx("postToolUseFailure", name, options)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
402
419
|
const ctx = this.buildHookContext("postToolUseFailure", name, rawArgsObj, options, {
|
|
403
420
|
errorMessage: `Tool "${name}" not found`,
|
|
404
421
|
failureKind: "tool_error"
|
|
@@ -411,32 +428,56 @@ var ToolRegistry = class {
|
|
|
411
428
|
}
|
|
412
429
|
let workingInput = rawArgsObj;
|
|
413
430
|
try {
|
|
414
|
-
|
|
431
|
+
const initial = tool.parameters.safeParse(args);
|
|
432
|
+
if (!initial.success) {
|
|
433
|
+
const msg = `Invalid arguments for tool "${name}": ${initial.error.issues.map((i) => i.message).join(", ")}`;
|
|
434
|
+
if (hookMgr) {
|
|
435
|
+
this.hookObserver?.onHookStart?.(
|
|
436
|
+
this.hookObserverCtx("postToolUseFailure", name, options)
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
await hookMgr?.executePostToolUseFailure(
|
|
440
|
+
this.buildHookContext("postToolUseFailure", name, rawArgsObj, options, {
|
|
441
|
+
errorMessage: msg,
|
|
442
|
+
failureKind: "validation"
|
|
443
|
+
})
|
|
444
|
+
);
|
|
445
|
+
return { content: msg, isError: true };
|
|
446
|
+
}
|
|
447
|
+
workingInput = initial.data;
|
|
415
448
|
if (hookMgr) {
|
|
449
|
+
this.hookObserver?.onHookStart?.(
|
|
450
|
+
this.hookObserverCtx("preToolUse", name, options)
|
|
451
|
+
);
|
|
416
452
|
const pre = await hookMgr.executePreToolUse(
|
|
417
453
|
this.buildHookContext("preToolUse", name, workingInput, options)
|
|
418
454
|
);
|
|
455
|
+
this.hookObserver?.onHookDecision?.({
|
|
456
|
+
...this.hookObserverCtx("preToolUse", name, options),
|
|
457
|
+
allowed: pre.allowed,
|
|
458
|
+
reason: pre.reason
|
|
459
|
+
});
|
|
419
460
|
if (!pre.allowed) {
|
|
420
461
|
return {
|
|
421
462
|
content: pre.reason ?? "Blocked by hook",
|
|
422
463
|
isError: true
|
|
423
464
|
};
|
|
424
465
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
)
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
throw err;
|
|
466
|
+
const merged = tool.parameters.safeParse(pre.updatedInput ?? workingInput);
|
|
467
|
+
if (!merged.success) {
|
|
468
|
+
const msg = `Invalid arguments after hook merge for tool "${name}": ${merged.error.issues.map((i) => i.message).join(", ")}`;
|
|
469
|
+
this.hookObserver?.onHookStart?.(
|
|
470
|
+
this.hookObserverCtx("postToolUseFailure", name, options)
|
|
471
|
+
);
|
|
472
|
+
await hookMgr.executePostToolUseFailure(
|
|
473
|
+
this.buildHookContext("postToolUseFailure", name, workingInput, options, {
|
|
474
|
+
errorMessage: msg,
|
|
475
|
+
failureKind: "validation"
|
|
476
|
+
})
|
|
477
|
+
);
|
|
478
|
+
return { content: msg, isError: true };
|
|
439
479
|
}
|
|
480
|
+
workingInput = merged.data;
|
|
440
481
|
}
|
|
441
482
|
const handlerArgs = workingInput;
|
|
442
483
|
const executionContext = {
|
|
@@ -447,6 +488,11 @@ var ToolRegistry = class {
|
|
|
447
488
|
const result = await tool.handler(handlerArgs, executionContext);
|
|
448
489
|
const toolResultRaw = result;
|
|
449
490
|
if (result.isError) {
|
|
491
|
+
if (hookMgr) {
|
|
492
|
+
this.hookObserver?.onHookStart?.(
|
|
493
|
+
this.hookObserverCtx("postToolUseFailure", name, options)
|
|
494
|
+
);
|
|
495
|
+
}
|
|
450
496
|
await hookMgr?.executePostToolUseFailure(
|
|
451
497
|
this.buildHookContext("postToolUseFailure", name, workingInput, options, {
|
|
452
498
|
errorMessage: result.content,
|
|
@@ -464,6 +510,11 @@ var ToolRegistry = class {
|
|
|
464
510
|
{ args: handlerArgs }
|
|
465
511
|
);
|
|
466
512
|
}
|
|
513
|
+
if (hookMgr) {
|
|
514
|
+
this.hookObserver?.onHookStart?.(
|
|
515
|
+
this.hookObserverCtx("postToolUse", name, options)
|
|
516
|
+
);
|
|
517
|
+
}
|
|
467
518
|
await hookMgr?.executePostToolUse(
|
|
468
519
|
this.buildHookContext("postToolUse", name, workingInput, options, {
|
|
469
520
|
toolResultRaw,
|
|
@@ -472,20 +523,12 @@ var ToolRegistry = class {
|
|
|
472
523
|
);
|
|
473
524
|
return finalResult;
|
|
474
525
|
} catch (error) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
this.
|
|
479
|
-
errorMessage: msg2,
|
|
480
|
-
failureKind: "validation"
|
|
481
|
-
})
|
|
526
|
+
const msg = `Error executing tool "${name}": ${error instanceof Error ? error.message : String(error)}`;
|
|
527
|
+
if (hookMgr) {
|
|
528
|
+
this.hookObserver?.onHookStart?.(
|
|
529
|
+
this.hookObserverCtx("postToolUseFailure", name, options)
|
|
482
530
|
);
|
|
483
|
-
return {
|
|
484
|
-
content: msg2,
|
|
485
|
-
isError: true
|
|
486
|
-
};
|
|
487
531
|
}
|
|
488
|
-
const msg = `Error executing tool "${name}": ${error instanceof Error ? error.message : String(error)}`;
|
|
489
532
|
await hookMgr?.executePostToolUseFailure(
|
|
490
533
|
this.buildHookContext("postToolUseFailure", name, workingInput, options, {
|
|
491
534
|
errorMessage: msg,
|
|
@@ -505,7 +548,7 @@ var ToolRegistry = class {
|
|
|
505
548
|
return this.getAll().map((tool) => ({
|
|
506
549
|
name: tool.name,
|
|
507
550
|
description: tool.description,
|
|
508
|
-
parameters:
|
|
551
|
+
parameters: chunkOZO7D77N_cjs.zodToJsonSchema(tool.parameters)
|
|
509
552
|
}));
|
|
510
553
|
}
|
|
511
554
|
/**
|
|
@@ -561,7 +604,7 @@ var ToolRegistry = class {
|
|
|
561
604
|
return this.getAll().map((tool) => ({
|
|
562
605
|
name: tool.name,
|
|
563
606
|
description: tool.description,
|
|
564
|
-
parameters:
|
|
607
|
+
parameters: chunkOZO7D77N_cjs.zodToJsonSchema(tool.parameters)
|
|
565
608
|
}));
|
|
566
609
|
}
|
|
567
610
|
};
|
|
@@ -832,10 +875,94 @@ var MAX_LINE_LENGTH = 2e3;
|
|
|
832
875
|
var MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`;
|
|
833
876
|
var MAX_BYTES = 50 * 1024;
|
|
834
877
|
var MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`;
|
|
878
|
+
var EDIT_MAX_FILE_BYTES = 1024 ** 3;
|
|
879
|
+
function detectDominantEol(content) {
|
|
880
|
+
let crlf = 0;
|
|
881
|
+
for (let i = 0; i < content.length - 1; i++) {
|
|
882
|
+
if (content[i] === "\r" && content[i + 1] === "\n") {
|
|
883
|
+
crlf++;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
let nl = 0;
|
|
887
|
+
for (let i = 0; i < content.length; i++) {
|
|
888
|
+
if (content[i] === "\n") {
|
|
889
|
+
nl++;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const bareLf = nl - crlf;
|
|
893
|
+
if (crlf > bareLf) {
|
|
894
|
+
return "\r\n";
|
|
895
|
+
}
|
|
896
|
+
return "\n";
|
|
897
|
+
}
|
|
898
|
+
function normalizeNewStringEols(text, eol) {
|
|
899
|
+
const unified = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
900
|
+
if (eol === "\n") {
|
|
901
|
+
return unified;
|
|
902
|
+
}
|
|
903
|
+
return unified.replace(/\n/g, "\r\n");
|
|
904
|
+
}
|
|
905
|
+
function buildNeedleCandidates(oldString, dominantEol) {
|
|
906
|
+
const out = [oldString];
|
|
907
|
+
if (dominantEol === "\r\n") {
|
|
908
|
+
if (!oldString.includes("\r")) {
|
|
909
|
+
const v = oldString.replace(/\n/g, "\r\n");
|
|
910
|
+
if (v !== oldString) {
|
|
911
|
+
out.push(v);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
} else {
|
|
915
|
+
if (oldString.includes("\r\n")) {
|
|
916
|
+
const v = oldString.replace(/\r\n/g, "\n");
|
|
917
|
+
if (v !== oldString) {
|
|
918
|
+
out.push(v);
|
|
919
|
+
}
|
|
920
|
+
} else if (oldString.includes("\r")) {
|
|
921
|
+
const v = oldString.replace(/\r/g, "\n");
|
|
922
|
+
if (v !== oldString) {
|
|
923
|
+
out.push(v);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return out;
|
|
928
|
+
}
|
|
929
|
+
function countOccurrences(haystack, needle) {
|
|
930
|
+
if (needle.length === 0) {
|
|
931
|
+
return 0;
|
|
932
|
+
}
|
|
933
|
+
let n = 0;
|
|
934
|
+
let from = 0;
|
|
935
|
+
let i = 0;
|
|
936
|
+
while ((i = haystack.indexOf(needle, from)) !== -1) {
|
|
937
|
+
n++;
|
|
938
|
+
from = i + needle.length;
|
|
939
|
+
}
|
|
940
|
+
return n;
|
|
941
|
+
}
|
|
942
|
+
function replaceNonOverlapping(content, needle, replacement, replaceAll) {
|
|
943
|
+
if (!replaceAll) {
|
|
944
|
+
const i2 = content.indexOf(needle);
|
|
945
|
+
if (i2 === -1) {
|
|
946
|
+
throw new Error("Edit: needle not found after resolution (internal inconsistency)");
|
|
947
|
+
}
|
|
948
|
+
return content.slice(0, i2) + replacement + content.slice(i2 + needle.length);
|
|
949
|
+
}
|
|
950
|
+
let out = "";
|
|
951
|
+
let from = 0;
|
|
952
|
+
let i = 0;
|
|
953
|
+
while ((i = content.indexOf(needle, from)) !== -1) {
|
|
954
|
+
out += content.slice(from, i) + replacement;
|
|
955
|
+
from = i + needle.length;
|
|
956
|
+
}
|
|
957
|
+
out += content.slice(from);
|
|
958
|
+
return out;
|
|
959
|
+
}
|
|
835
960
|
var readFileTool = createTool({
|
|
836
961
|
name: "Read",
|
|
837
962
|
category: "filesystem",
|
|
838
|
-
description: `Reads
|
|
963
|
+
description: `Reads human-readable text from the local filesystem: source code, configuration, logs, Markdown, and structured text (JSON, XML, YAML, etc.).
|
|
964
|
+
|
|
965
|
+
Do NOT use Read for binary formats. This tool decodes the file as text; for binaries the result is garbage or misleading. Examples: images (png, jpg, gif, webp, ico), Office/OpenXML (xlsx, docx, pptx), PDF, audio/video, archives (zip, gz, etc.), and compiled binaries. Prefer format-specific tooling, a small script or library in the user's environment, or ask the user for an exported/plain-text view.
|
|
839
966
|
|
|
840
967
|
Usage:
|
|
841
968
|
- The file_path parameter must be an absolute path, not a relative path
|
|
@@ -844,10 +971,12 @@ Usage:
|
|
|
844
971
|
- Results are returned using cat -n style, with line numbers starting at 1
|
|
845
972
|
- Lines longer than 2000 characters are truncated
|
|
846
973
|
- Use the offset and limit parameters to read specific line ranges of large files
|
|
847
|
-
-
|
|
974
|
+
- An empty file (no lines) returns successfully with no numbered lines and a suffix noting zero total lines\u2014it is not an error
|
|
848
975
|
- Text encoding is detected automatically from the file (BOM, UTF-8 validity, charset analysis). You rarely need to set encoding; use it only to override detection (e.g. gbk, gb18030, cp936 maps to gbk)`,
|
|
849
976
|
parameters: zod.z.object({
|
|
850
|
-
file_path: zod.z.string().describe(
|
|
977
|
+
file_path: zod.z.string().describe(
|
|
978
|
+
"Absolute path to a text or text-decodable source file (not binary formats such as images, xlsx, or pdf)."
|
|
979
|
+
),
|
|
851
980
|
encoding: zod.z.string().optional().describe(
|
|
852
981
|
'Optional. Omit or use "auto" for automatic detection (default). Set only to force a specific encoding (utf8, gbk, gb18030, latin1, etc.; cp936 is treated as gbk).'
|
|
853
982
|
),
|
|
@@ -1018,7 +1147,9 @@ var editTool = createTool({
|
|
|
1018
1147
|
|
|
1019
1148
|
Usage:
|
|
1020
1149
|
- You must use the Read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file
|
|
1150
|
+
- Files at or above 1 GiB cannot be edited with this tool (use another workflow for huge files)
|
|
1021
1151
|
- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: line number + tab. Everything after that is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string
|
|
1152
|
+
- old_string may use \\n line breaks; CRLF files are matched and new_string is rewritten to the file's dominant line ending style (\\r\\n vs \\n)
|
|
1022
1153
|
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required
|
|
1023
1154
|
- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked
|
|
1024
1155
|
- The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string
|
|
@@ -1026,7 +1157,7 @@ Usage:
|
|
|
1026
1157
|
- For non-UTF-8 files, set encoding to the same value you used with Read (default is utf8)`,
|
|
1027
1158
|
parameters: zod.z.object({
|
|
1028
1159
|
file_path: zod.z.string().describe("The absolute path to the file to modify"),
|
|
1029
|
-
old_string: zod.z.string().describe("The text to replace"),
|
|
1160
|
+
old_string: zod.z.string().min(1).describe("The text to replace (non-empty)"),
|
|
1030
1161
|
new_string: zod.z.string().describe("The text to replace it with (must be different from old_string)"),
|
|
1031
1162
|
replace_all: zod.z.boolean().default(false).describe("Replace all occurrences of old_string (default false)"),
|
|
1032
1163
|
encoding: zod.z.string().optional().describe(
|
|
@@ -1048,25 +1179,46 @@ Usage:
|
|
|
1048
1179
|
isError: true
|
|
1049
1180
|
};
|
|
1050
1181
|
}
|
|
1182
|
+
const fs = await import('fs/promises');
|
|
1183
|
+
const stat = await fs.stat(file_path);
|
|
1184
|
+
if (!stat.isFile()) {
|
|
1185
|
+
return {
|
|
1186
|
+
content: `Error: ${file_path} is not a file`,
|
|
1187
|
+
isError: true
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
if (stat.size >= EDIT_MAX_FILE_BYTES) {
|
|
1191
|
+
return {
|
|
1192
|
+
content: `Error: file is too large to edit (${stat.size} bytes). Maximum size is ${EDIT_MAX_FILE_BYTES} bytes (1 GiB). Use a different tool or split the work.`,
|
|
1193
|
+
isError: true
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1051
1196
|
const content = await readFileAsUnicodeString(file_path, normalized);
|
|
1052
|
-
|
|
1197
|
+
const dominantEol = detectDominantEol(content);
|
|
1198
|
+
const candidates = buildNeedleCandidates(old_string, dominantEol);
|
|
1199
|
+
let needle = null;
|
|
1200
|
+
for (const c of candidates) {
|
|
1201
|
+
if (countOccurrences(content, c) > 0) {
|
|
1202
|
+
needle = c;
|
|
1203
|
+
break;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
if (needle === null) {
|
|
1053
1207
|
return {
|
|
1054
1208
|
content: `old_string not found in ${file_path}`,
|
|
1055
1209
|
isError: true
|
|
1056
1210
|
};
|
|
1057
1211
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1212
|
+
const occurrences = countOccurrences(content, needle);
|
|
1213
|
+
if (!replace_all && occurrences > 1) {
|
|
1214
|
+
return {
|
|
1215
|
+
content: `Found ${occurrences} matches for old_string. Provide more context to make it unique, or set replace_all to true.`,
|
|
1216
|
+
isError: true
|
|
1217
|
+
};
|
|
1066
1218
|
}
|
|
1067
|
-
const
|
|
1219
|
+
const normalizedNew = normalizeNewStringEols(new_string, dominantEol);
|
|
1220
|
+
const newContent = replaceNonOverlapping(content, needle, normalizedNew, replace_all);
|
|
1068
1221
|
await writeFileFromUnicodeString(file_path, newContent, normalized);
|
|
1069
|
-
const occurrences = replace_all ? content.split(old_string).length - 1 : 1;
|
|
1070
1222
|
return {
|
|
1071
1223
|
content: `Successfully edited ${file_path} (${occurrences} replacement${occurrences > 1 ? "s" : ""})`
|
|
1072
1224
|
};
|
|
@@ -1148,6 +1300,53 @@ function findInPath(executable) {
|
|
|
1148
1300
|
return null;
|
|
1149
1301
|
}
|
|
1150
1302
|
}
|
|
1303
|
+
function findGitBashNextToGitExe(gitExe) {
|
|
1304
|
+
if (!fs.existsSync(gitExe)) {
|
|
1305
|
+
return null;
|
|
1306
|
+
}
|
|
1307
|
+
const dir = path.win32.dirname(gitExe);
|
|
1308
|
+
const siblingBash = path.win32.join(dir, "bash.exe");
|
|
1309
|
+
if (fs.existsSync(siblingBash)) {
|
|
1310
|
+
return siblingBash;
|
|
1311
|
+
}
|
|
1312
|
+
let walk = dir;
|
|
1313
|
+
for (let i = 0; i < 4; i++) {
|
|
1314
|
+
const bashPath = path.win32.join(walk, "bin", "bash.exe");
|
|
1315
|
+
if (fs.existsSync(bashPath)) {
|
|
1316
|
+
return bashPath;
|
|
1317
|
+
}
|
|
1318
|
+
const parent = path.win32.dirname(walk);
|
|
1319
|
+
if (parent === walk) {
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
walk = parent;
|
|
1323
|
+
}
|
|
1324
|
+
return null;
|
|
1325
|
+
}
|
|
1326
|
+
function findBashViaGitInstall() {
|
|
1327
|
+
const gitExe = findInPath("git");
|
|
1328
|
+
if (!gitExe) {
|
|
1329
|
+
return null;
|
|
1330
|
+
}
|
|
1331
|
+
return findGitBashNextToGitExe(gitExe);
|
|
1332
|
+
}
|
|
1333
|
+
function findGitBashInDefaultInstallDirs() {
|
|
1334
|
+
const drives = ["C", "D", "E"];
|
|
1335
|
+
const relatives = [
|
|
1336
|
+
["Program Files", "Git", "bin", "bash.exe"],
|
|
1337
|
+
["Program Files (x86)", "Git", "bin", "bash.exe"]
|
|
1338
|
+
];
|
|
1339
|
+
for (const drive of drives) {
|
|
1340
|
+
const root = `${drive}:\\`;
|
|
1341
|
+
for (const parts of relatives) {
|
|
1342
|
+
const p = path.win32.join(root, ...parts);
|
|
1343
|
+
if (fs.existsSync(p)) {
|
|
1344
|
+
return p;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1151
1350
|
function getShellPath() {
|
|
1152
1351
|
if (cachedShellPath !== null) {
|
|
1153
1352
|
return cachedShellPath;
|
|
@@ -1158,15 +1357,15 @@ function getShellPath() {
|
|
|
1158
1357
|
cachedShellPath = bashPath;
|
|
1159
1358
|
return bashPath;
|
|
1160
1359
|
}
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1360
|
+
const viaGit = findBashViaGitInstall();
|
|
1361
|
+
if (viaGit) {
|
|
1362
|
+
cachedShellPath = viaGit;
|
|
1363
|
+
return viaGit;
|
|
1364
|
+
}
|
|
1365
|
+
const fromDirs = findGitBashInDefaultInstallDirs();
|
|
1366
|
+
if (fromDirs) {
|
|
1367
|
+
cachedShellPath = fromDirs;
|
|
1368
|
+
return fromDirs;
|
|
1170
1369
|
}
|
|
1171
1370
|
const pwshPath = findInPath("pwsh");
|
|
1172
1371
|
if (pwshPath) {
|
|
@@ -1990,128 +2189,52 @@ var webSearchTool = createTool({
|
|
|
1990
2189
|
function getWebTools() {
|
|
1991
2190
|
return [webFetchTool, webSearchTool];
|
|
1992
2191
|
}
|
|
1993
|
-
var
|
|
1994
|
-
var
|
|
1995
|
-
|
|
1996
|
-
name: "TaskCreate",
|
|
2192
|
+
var todoStatusEnum = zod.z.enum(["pending", "in_progress", "completed"]);
|
|
2193
|
+
var todoWriteTool = createTool({
|
|
2194
|
+
name: "TodoWrite",
|
|
1997
2195
|
category: "planning",
|
|
1998
|
-
description: `
|
|
2196
|
+
description: `MUST USE for multi-step tasks. Creates a structured task list to track progress. Call this tool FIRST before executing any complex task.
|
|
1999
2197
|
|
|
2000
|
-
|
|
2198
|
+
Any number of tasks may be "in_progress" when work runs in parallel. Zero in_progress is fine (e.g. all pending or all completed).
|
|
2001
2199
|
|
|
2002
|
-
|
|
2003
|
-
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
2004
|
-
- User explicitly requests todo list - When the user directly asks you to use the task list
|
|
2005
|
-
- User provides multiple tasks - When users provide a list of things to be done
|
|
2200
|
+
**Before you finish your assistant response for a multi-step request**, call \`TodoWrite\` again so **every** item in the list has status \`completed\`, unless you are explicitly pausing mid-work for a follow-up turn. Do not leave dangling \`pending\` or \`in_progress\` items when the work for this request is done.
|
|
2006
2201
|
|
|
2007
|
-
|
|
2202
|
+
**Replanning:** If execution shows the earlier plan was wrong, incomplete, or no longer fits (wrong order, missing steps, obsolete items), call \`TodoWrite\` anytime with an updated full list\u2014add, remove, merge, or rewrite steps as needed.
|
|
2008
2203
|
|
|
2009
|
-
-
|
|
2010
|
-
|
|
2011
|
-
- The task can be completed in less than 3 trivial steps
|
|
2012
|
-
|
|
2013
|
-
All tasks are created with status pending.`,
|
|
2204
|
+
Triggers: multi-step tasks, multiple files/components, user provides task list.
|
|
2205
|
+
Skip: single simple task, informational questions.`,
|
|
2014
2206
|
parameters: zod.z.object({
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
...activeForm && { activeForm }
|
|
2027
|
-
};
|
|
2028
|
-
tasks.set(id, task);
|
|
2029
|
-
return {
|
|
2030
|
-
content: `Task created [${id}]: ${subject}`,
|
|
2031
|
-
metadata: { task }
|
|
2032
|
-
};
|
|
2033
|
-
}
|
|
2034
|
-
});
|
|
2035
|
-
var taskUpdateTool = createTool({
|
|
2036
|
-
name: "TaskUpdate",
|
|
2037
|
-
category: "planning",
|
|
2038
|
-
description: `Use this tool to update a task in the task list.
|
|
2039
|
-
|
|
2040
|
-
## When to Use This Tool
|
|
2041
|
-
|
|
2042
|
-
**Mark tasks as completed:**
|
|
2043
|
-
- When you have completed the work described in a task
|
|
2044
|
-
- IMPORTANT: Always mark your assigned tasks as completed when you finish them
|
|
2045
|
-
|
|
2046
|
-
**Delete tasks:**
|
|
2047
|
-
- When a task is no longer relevant or was created in error
|
|
2048
|
-
|
|
2049
|
-
## Status Workflow
|
|
2050
|
-
|
|
2051
|
-
Status progresses: pending \u2192 in_progress \u2192 completed`,
|
|
2052
|
-
parameters: zod.z.object({
|
|
2053
|
-
taskId: zod.z.string().describe("The ID of the task to update"),
|
|
2054
|
-
status: zod.z.enum(["pending", "in_progress", "completed", "deleted"]).optional().describe("New status for the task"),
|
|
2055
|
-
subject: zod.z.string().optional().describe("New subject for the task"),
|
|
2056
|
-
description: zod.z.string().optional().describe("New description for the task"),
|
|
2057
|
-
activeForm: zod.z.string().optional().describe("Present continuous form shown in spinner when in_progress")
|
|
2207
|
+
todos: zod.z.array(
|
|
2208
|
+
zod.z.object({
|
|
2209
|
+
content: zod.z.string().describe('Brief description of the task in imperative form (e.g., "Run tests")'),
|
|
2210
|
+
activeForm: zod.z.string().optional().describe(
|
|
2211
|
+
'Optional present-continuous label for in-progress UI (e.g., "Running tests"). Omit if not needed.'
|
|
2212
|
+
),
|
|
2213
|
+
status: todoStatusEnum.describe("Task status: pending, in_progress, or completed")
|
|
2214
|
+
})
|
|
2215
|
+
).min(1).describe(
|
|
2216
|
+
"Full updated todo list. Refresh this whenever progress or the plan changes. When finishing the multi-step work, all entries should be completed."
|
|
2217
|
+
)
|
|
2058
2218
|
}),
|
|
2059
|
-
handler: async ({
|
|
2060
|
-
const task = tasks.get(taskId);
|
|
2061
|
-
if (!task) {
|
|
2062
|
-
return {
|
|
2063
|
-
content: `Task ${taskId} not found`,
|
|
2064
|
-
isError: true
|
|
2065
|
-
};
|
|
2066
|
-
}
|
|
2067
|
-
if (status === "deleted") {
|
|
2068
|
-
tasks.delete(taskId);
|
|
2069
|
-
return { content: `Task ${taskId} deleted` };
|
|
2070
|
-
}
|
|
2071
|
-
if (status) task.status = status;
|
|
2072
|
-
if (subject) task.subject = subject;
|
|
2073
|
-
if (description) task.description = description;
|
|
2074
|
-
if (activeForm) task.activeForm = activeForm;
|
|
2075
|
-
const icon = task.status === "completed" ? "x" : task.status === "in_progress" ? ">" : " ";
|
|
2076
|
-
return {
|
|
2077
|
-
content: `Task [${taskId}] updated: [${icon}] ${task.subject}`,
|
|
2078
|
-
metadata: { task }
|
|
2079
|
-
};
|
|
2080
|
-
}
|
|
2081
|
-
});
|
|
2082
|
-
var taskListTool = createTool({
|
|
2083
|
-
name: "TaskList",
|
|
2084
|
-
category: "planning",
|
|
2085
|
-
description: `Use this tool to list all tasks in the task list.
|
|
2086
|
-
|
|
2087
|
-
## Output
|
|
2088
|
-
|
|
2089
|
-
Returns a summary of each task:
|
|
2090
|
-
- id: Task identifier (use with TaskUpdate)
|
|
2091
|
-
- subject: Brief description of the task
|
|
2092
|
-
- status: pending, in_progress, or completed`,
|
|
2093
|
-
parameters: zod.z.object({}),
|
|
2094
|
-
handler: async () => {
|
|
2095
|
-
if (tasks.size === 0) {
|
|
2096
|
-
return { content: "No tasks in the list." };
|
|
2097
|
-
}
|
|
2219
|
+
handler: async ({ todos }) => {
|
|
2098
2220
|
const lines = [];
|
|
2099
|
-
for (const
|
|
2100
|
-
const icon =
|
|
2101
|
-
lines.push(`[${icon}]
|
|
2221
|
+
for (const todo of todos) {
|
|
2222
|
+
const icon = todo.status === "completed" ? "x" : todo.status === "in_progress" ? ">" : " ";
|
|
2223
|
+
lines.push(`[${icon}] ${todo.content}`);
|
|
2102
2224
|
}
|
|
2103
|
-
const pending =
|
|
2104
|
-
const inProgress =
|
|
2105
|
-
const completed =
|
|
2225
|
+
const pending = todos.filter((todo) => todo.status === "pending").length;
|
|
2226
|
+
const inProgress = todos.filter((todo) => todo.status === "in_progress").length;
|
|
2227
|
+
const completed = todos.filter((todo) => todo.status === "completed").length;
|
|
2106
2228
|
return {
|
|
2107
|
-
content: `
|
|
2229
|
+
content: `Task list updated (${completed} completed, ${inProgress} in progress, ${pending} pending):
|
|
2108
2230
|
|
|
2109
|
-
${lines.join("\n")}
|
|
2231
|
+
${lines.join("\n")}`,
|
|
2232
|
+
metadata: { todos }
|
|
2110
2233
|
};
|
|
2111
2234
|
}
|
|
2112
2235
|
});
|
|
2113
|
-
function
|
|
2114
|
-
return [
|
|
2236
|
+
function getPlanningTools() {
|
|
2237
|
+
return [todoWriteTool];
|
|
2115
2238
|
}
|
|
2116
2239
|
var questionsSchema = zod.z.object({
|
|
2117
2240
|
questions: zod.z.array(
|
|
@@ -2322,7 +2445,7 @@ function getAllBuiltinTools(skillRegistry, interactionOptions) {
|
|
|
2322
2445
|
...getShellTools(),
|
|
2323
2446
|
...getGrepTools(),
|
|
2324
2447
|
...getWebTools(),
|
|
2325
|
-
...
|
|
2448
|
+
...getPlanningTools(),
|
|
2326
2449
|
...getInteractionTools(interactionOptions),
|
|
2327
2450
|
...getSubagentTools(),
|
|
2328
2451
|
...getSkillTools(skillRegistry)
|
|
@@ -2761,11 +2884,11 @@ exports.getFileSystemTools = getFileSystemTools;
|
|
|
2761
2884
|
exports.getGlobalRegistry = getGlobalRegistry;
|
|
2762
2885
|
exports.getGrepTools = getGrepTools;
|
|
2763
2886
|
exports.getInteractionTools = getInteractionTools;
|
|
2887
|
+
exports.getPlanningTools = getPlanningTools;
|
|
2764
2888
|
exports.getSafeBuiltinTools = getSafeBuiltinTools;
|
|
2765
2889
|
exports.getShellTools = getShellTools;
|
|
2766
2890
|
exports.getSkillTools = getSkillTools;
|
|
2767
2891
|
exports.getSubagentTools = getSubagentTools;
|
|
2768
|
-
exports.getTaskTools = getTaskTools;
|
|
2769
2892
|
exports.getWebTools = getWebTools;
|
|
2770
2893
|
exports.globTool = globTool;
|
|
2771
2894
|
exports.grepTool = grepTool;
|
|
@@ -2777,12 +2900,10 @@ exports.parseHooksSettingsFile = parseHooksSettingsFile;
|
|
|
2777
2900
|
exports.questionTool = questionTool;
|
|
2778
2901
|
exports.readFileTool = readFileTool;
|
|
2779
2902
|
exports.subagentRequestSchema = subagentRequestSchema;
|
|
2780
|
-
exports.
|
|
2781
|
-
exports.taskListTool = taskListTool;
|
|
2782
|
-
exports.taskUpdateTool = taskUpdateTool;
|
|
2903
|
+
exports.todoWriteTool = todoWriteTool;
|
|
2783
2904
|
exports.truncateMatchLineForDisplay = truncateMatchLineForDisplay;
|
|
2784
2905
|
exports.webFetchTool = webFetchTool;
|
|
2785
2906
|
exports.webSearchTool = webSearchTool;
|
|
2786
2907
|
exports.writeFileTool = writeFileTool;
|
|
2787
|
-
//# sourceMappingURL=chunk-
|
|
2788
|
-
//# sourceMappingURL=chunk-
|
|
2908
|
+
//# sourceMappingURL=chunk-Z45DHTDX.cjs.map
|
|
2909
|
+
//# sourceMappingURL=chunk-Z45DHTDX.cjs.map
|