@zqagent/core 0.3.13 → 0.3.16
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/{TurnEngine-BZjUGic_.d.ts → TurnEngine-C8qqbilC.d.ts} +18 -3
- package/dist/{TurnEngine-CMGdcSdp.d.cts → TurnEngine-DKSczYaA.d.cts} +18 -3
- package/dist/{conflictGuard-BBOOIxxK.d.cts → conflictGuard-BuICnWEI.d.cts} +8 -0
- package/dist/{conflictGuard-BBOOIxxK.d.ts → conflictGuard-BuICnWEI.d.ts} +8 -0
- package/dist/index.cjs +3372 -1136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +221 -6
- package/dist/index.d.ts +221 -6
- package/dist/index.js +3391 -1155
- package/dist/index.js.map +1 -1
- package/dist/internal/engine/FileLogHook.d.cts +1 -1
- package/dist/internal/engine/FileLogHook.d.ts +1 -1
- package/dist/internal/update/controller.cjs +1 -1
- package/dist/internal/update/controller.js +1 -1
- package/dist/internal/update/platform.cjs +1 -1
- package/dist/internal/update/platform.js +1 -1
- package/dist/tools/diff.d.cts +1 -1
- package/dist/tools/diff.d.ts +1 -1
- package/dist/tools/explore.cjs +504 -127
- package/dist/tools/explore.cjs.map +1 -1
- package/dist/tools/explore.d.cts +1 -1
- package/dist/tools/explore.d.ts +1 -1
- package/dist/tools/explore.js +504 -127
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/files.cjs +267 -47
- package/dist/tools/files.cjs.map +1 -1
- package/dist/tools/files.d.cts +1 -1
- package/dist/tools/files.d.ts +1 -1
- package/dist/tools/files.js +267 -47
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/search.cjs +103 -24
- package/dist/tools/search.cjs.map +1 -1
- package/dist/tools/search.d.cts +8 -2
- package/dist/tools/search.d.ts +8 -2
- package/dist/tools/search.js +103 -24
- package/dist/tools/search.js.map +1 -1
- package/package.json +6 -5
package/dist/tools/explore.js
CHANGED
|
@@ -314,8 +314,17 @@ var zh = {
|
|
|
314
314
|
- \u4E0D\u8981\u5C06\u5B8C\u6574\u7684\u6587\u4EF6\u5185\u5BB9\u5F53\u4F5C\u771F\u7406\u3002\u53EA\u8BB0\u5F55\u67D0\u4E2A\u6587\u4EF6\u88AB\u8BFB\u53D6/\u7F16\u8F91\u8FC7\u8FD9\u4E00\u4E8B\u5B9E\uFF1B\u534F\u4F5C\u8005\u5982\u679C\u9700\u8981\u518D\u6B21\u83B7\u53D6\u5185\u5BB9\u4F1A\u91CD\u65B0\u8BFB\u53D6\u3002\u9648\u65E7\u7684\u6587\u4EF6\u8BB0\u5FC6\u6BD4\u6CA1\u6709\u8BB0\u5FC6\u66F4\u7CDF\u7CD5\u3002
|
|
315
315
|
- \u82E5\u63D0\u4F9B\u4E86\u4E0A\u4E00\u7248\u6458\u8981\uFF1A\u53EA\u628A\u5B83\u4ECD\u7136\u6709\u6548\u7684\u7ED3\u8BBA\u5E76\u5165\u5BF9\u5E94\u7AE0\u8282\uFF0C\u4E0D\u8981\u6574\u6BB5\u590D\u8FF0\u6216\u9010\u6761\u8F6C\u6284\u3002
|
|
316
316
|
- \u8981\u5177\u4F53\uFF1A\u8DEF\u5F84\u3001\u540D\u79F0\u3001\u547D\u4EE4\u3001id\u2014\u2014\u800C\u4E0D\u662F\u6A21\u7CCA\u7684\u5F15\u7528\u3002
|
|
317
|
+
- \u7528\u7B80\u4F53\u4E2D\u6587\u64B0\u5199\u6458\u8981\u3002\u6458\u8981\u5728\u540E\u7EED\u6BCF\u4E00\u8F6E\u90FD\u4F1A\u968F\u4E0A\u4E0B\u6587\u91CD\u53D1\uFF0C\u8BED\u8A00\u4E0D\u4E00\u81F4\u4F1A\u8BA9\u534F\u4F5C\u8005\u6539\u7528\u82F1\u6587\u4F5C\u7B54\u3002
|
|
317
318
|
- \u4EC5\u8F93\u51FA\u6458\u8981\u7AE0\u8282\uFF0C\u4E0D\u9644\u52A0\u524D\u8A00\u3002`,
|
|
318
319
|
continuationContract: "\u4ECE\u4F60\u4E4B\u524D\u4E2D\u65AD\u7684\u5730\u65B9\u7EE7\u7EED\uFF1A\u5B8C\u5168\u6309\u7167\u63CF\u8FF0\u63A5\u7EED\u5F53\u524D\u5DE5\u4F5C\u548C\u4E0B\u4E00\u6B65\u3002\u4E0D\u8981\u91CD\u65B0\u8BE2\u95EE\u5DF2\u56DE\u7B54\u7684\u95EE\u9898\uFF0C\u4E0D\u8981\u56DE\u987E\uFF0C\u4E0D\u8981\u63D0\u53CA\u4E0A\u4E0B\u6587\u5DF2\u88AB\u538B\u7F29\u3002\u5982\u679C\u4F60\u9700\u8981\u4E0A\u8FF0\u63D0\u5230\u7684\u6587\u4EF6\u7684\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u5B83\u3002",
|
|
320
|
+
compactedIntro: "\u672C\u4F1A\u8BDD\u8F83\u65E9\u7684\u8F6E\u6B21\u5DF2\u88AB\u538B\u7F29\u3002\u4E0B\u9762\u7684\u6458\u8981\u5C31\u662F\u4F60\u5BF9\u90A3\u4E9B\u8F6E\u6B21\u7684\u8BB0\u5FC6\u3002",
|
|
321
|
+
compactedUserMessagesHeader: "## \u538B\u7F29\u533A\u95F4\u5185\u7684\u7528\u6237\u6D88\u606F\uFF08\u539F\u6587\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09",
|
|
322
|
+
compactedOmittedNote: (n) => `\uFF08\u66F4\u65E9\u7684 ${n} \u6761\u7528\u6237\u6D88\u606F\u5DF2\u7701\u7565 \u2014\u2014 \u5176\u610F\u56FE\u5DF2\u5305\u542B\u5728\u4E0A\u9762\u7684\u6458\u8981\u4E2D\uFF09`,
|
|
323
|
+
compactedTrimmedNote: "\uFF08\u8F83\u65E9\u7684\u8F6E\u6B21\u56E0\u4E0A\u4E0B\u6587\u7A97\u53E3\u9650\u5236\u88AB\u88C1\u526A\uFF0C\u6CA1\u6709\u53EF\u7528\u6458\u8981\u3002\u5982\u679C\u9700\u8981\u65E9\u5148\u7684\u7ED3\u679C\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u6216\u91CD\u65B0\u6267\u884C\u547D\u4EE4\u3002\uFF09",
|
|
324
|
+
workingStateHeader: "## \u5DE5\u4F5C\u72B6\u6001\uFF08\u4ECE\u5DE5\u5177\u8BB0\u5F55\u4E2D\u673A\u68B0\u63D0\u53D6\uFF09",
|
|
325
|
+
workingStateFiles: "\u5DF2\u5199\u5165/\u4FEE\u6539\u7684\u6587\u4EF6\uFF08\u6700\u8FD1\u7684\u5728\u524D\uFF09\uFF1A",
|
|
326
|
+
workingStateCommands: "\u6700\u8FD1\u7684 shell \u547D\u4EE4\uFF1A",
|
|
327
|
+
workingStateTools: (list) => `\u538B\u7F29\u533A\u95F4\u5185\u4F7F\u7528\u8FC7\u7684\u5DE5\u5177\uFF1A${list}`,
|
|
319
328
|
genCommitMessageInstructions: `\u4F60\u662F Git \u63D0\u4EA4\u8BF4\u660E\u751F\u6210\u52A9\u624B\u3002\u6839\u636E\u7ED9\u5B9A\u7684\u4EE3\u7801\u5DEE\u5F02\uFF0C\u751F\u6210\u4E00\u6761\u51C6\u786E\u3001\u7B80\u6D01\u7684\u63D0\u4EA4\u8BF4\u660E\u3002
|
|
320
329
|
|
|
321
330
|
\u8981\u6C42\uFF1A
|
|
@@ -469,8 +478,17 @@ Rules:
|
|
|
469
478
|
- Do not treat full file contents as truth. Record only the fact that a file was read/edited; the collaborator will re-read it if it needs the content again. Stale file memory is worse than no memory.
|
|
470
479
|
- If a previous summary is provided: fold only its still-valid conclusions into the matching sections; do not restate it wholesale or copy it entry by entry.
|
|
471
480
|
- Be specific: paths, names, commands, ids \u2014 not vague references.
|
|
481
|
+
- Write the summary in English. It is re-sent with the context on every later turn; a language mismatch makes the collaborator switch to another language.
|
|
472
482
|
- Output only the summary sections, with no preamble.`,
|
|
473
483
|
continuationContract: "Continue from where you left off: pick up the current work and next step exactly as described. Do not re-ask questions that were already answered, do not recap, and do not mention that the context was compacted. If you need the contents of a file mentioned above, read it again.",
|
|
484
|
+
compactedIntro: "Earlier turns of this session were compacted. The summary below is your memory of them.",
|
|
485
|
+
compactedUserMessagesHeader: "## User messages in the compacted span (verbatim, chronological)",
|
|
486
|
+
compactedOmittedNote: (n) => `(${n} earlier user messages omitted \u2014 their intent is covered by the summary above)`,
|
|
487
|
+
compactedTrimmedNote: "(Older turns were trimmed to fit the context window; no summary is available for them. Re-read files and re-run commands if earlier results are needed.)",
|
|
488
|
+
workingStateHeader: "## Working state (extracted mechanically from tool records)",
|
|
489
|
+
workingStateFiles: "Files written/edited (most recent first):",
|
|
490
|
+
workingStateCommands: "Recent shell commands:",
|
|
491
|
+
workingStateTools: (list) => `Tools used in the summarized span: ${list}`,
|
|
474
492
|
genCommitMessageInstructions: `You are a Git commit message assistant. Given a code diff, produce an accurate, concise commit message.
|
|
475
493
|
|
|
476
494
|
Requirements:
|
|
@@ -624,8 +642,17 @@ var zhTW = {
|
|
|
624
642
|
- \u4E0D\u8981\u5C07\u5B8C\u6574\u7684\u6A94\u6848\u5167\u5BB9\u7576\u4F5C\u771F\u7406\u3002\u53EA\u8A18\u9304\u67D0\u500B\u6A94\u6848\u88AB\u8B80\u53D6/\u7DE8\u8F2F\u904E\u9019\u4E00\u4E8B\u5BE6\uFF1B\u5354\u4F5C\u8005\u5982\u679C\u9700\u8981\u518D\u6B21\u7372\u53D6\u5167\u5BB9\u6703\u91CD\u65B0\u8B80\u53D6\u3002\u9673\u820A\u7684\u6A94\u6848\u8A18\u61B6\u6BD4\u6C92\u6709\u8A18\u61B6\u66F4\u7CDF\u7CD5\u3002
|
|
625
643
|
- \u82E5\u63D0\u4F9B\u4E86\u4E0A\u4E00\u7248\u6458\u8981\uFF1A\u53EA\u628A\u5B83\u4ECD\u7136\u6709\u6548\u7684\u7D50\u8AD6\u4F75\u5165\u5C0D\u61C9\u7AE0\u7BC0\uFF0C\u4E0D\u8981\u6574\u6BB5\u8907\u8FF0\u6216\u9010\u689D\u8F49\u6284\u3002
|
|
626
644
|
- \u8981\u5177\u9AD4\uFF1A\u8DEF\u5F91\u3001\u540D\u7A31\u3001\u547D\u4EE4\u3001id\u2014\u2014\u800C\u4E0D\u662F\u6A21\u7CCA\u7684\u5F15\u7528\u3002
|
|
645
|
+
- \u7528\u7E41\u9AD4\u4E2D\u6587\u64B0\u5BEB\u6458\u8981\u3002\u6458\u8981\u5728\u5F8C\u7E8C\u6BCF\u4E00\u8F2A\u90FD\u6703\u96A8\u4E0A\u4E0B\u6587\u91CD\u767C\uFF0C\u8A9E\u8A00\u4E0D\u4E00\u81F4\u6703\u8B93\u5354\u4F5C\u8005\u6539\u7528\u5176\u4ED6\u8A9E\u8A00\u4F5C\u7B54\u3002
|
|
627
646
|
- \u50C5\u8F38\u51FA\u6458\u8981\u7AE0\u7BC0\uFF0C\u4E0D\u9644\u52A0\u524D\u8A00\u3002`,
|
|
628
647
|
continuationContract: "\u5F9E\u4F60\u4E4B\u524D\u4E2D\u65B7\u7684\u5730\u65B9\u7E7C\u7E8C\uFF1A\u5B8C\u5168\u6309\u7167\u63CF\u8FF0\u63A5\u7E8C\u7576\u524D\u5DE5\u4F5C\u548C\u4E0B\u4E00\u6B65\u3002\u4E0D\u8981\u91CD\u65B0\u8A62\u554F\u5DF2\u56DE\u7B54\u7684\u554F\u984C\uFF0C\u4E0D\u8981\u56DE\u9867\uFF0C\u4E0D\u8981\u63D0\u53CA\u4E0A\u4E0B\u6587\u5DF2\u88AB\u58D3\u7E2E\u3002\u5982\u679C\u4F60\u9700\u8981\u4E0A\u8FF0\u63D0\u5230\u7684\u6A94\u6848\u7684\u5167\u5BB9\uFF0C\u8ACB\u91CD\u65B0\u8B80\u53D6\u5B83\u3002",
|
|
648
|
+
compactedIntro: "\u672C\u6703\u8A71\u8F03\u65E9\u7684\u8F2A\u6B21\u5DF2\u88AB\u58D3\u7E2E\u3002\u4E0B\u9762\u7684\u6458\u8981\u5C31\u662F\u4F60\u5C0D\u90A3\u4E9B\u8F2A\u6B21\u7684\u8A18\u61B6\u3002",
|
|
649
|
+
compactedUserMessagesHeader: "## \u58D3\u7E2E\u5340\u9593\u5167\u7684\u4F7F\u7528\u8005\u8A0A\u606F\uFF08\u539F\u6587\uFF0C\u6309\u6642\u9593\u9806\u5E8F\uFF09",
|
|
650
|
+
compactedOmittedNote: (n) => `\uFF08\u66F4\u65E9\u7684 ${n} \u5247\u4F7F\u7528\u8005\u8A0A\u606F\u5DF2\u7701\u7565 \u2014\u2014 \u5176\u610F\u5716\u5DF2\u5305\u542B\u5728\u4E0A\u9762\u7684\u6458\u8981\u4E2D\uFF09`,
|
|
651
|
+
compactedTrimmedNote: "\uFF08\u8F03\u65E9\u7684\u8F2A\u6B21\u56E0\u4E0A\u4E0B\u6587\u8996\u7A97\u9650\u5236\u88AB\u88C1\u526A\uFF0C\u6C92\u6709\u53EF\u7528\u6458\u8981\u3002\u5982\u679C\u9700\u8981\u65E9\u5148\u7684\u7D50\u679C\uFF0C\u8ACB\u91CD\u65B0\u8B80\u53D6\u6A94\u6848\u6216\u91CD\u65B0\u57F7\u884C\u547D\u4EE4\u3002\uFF09",
|
|
652
|
+
workingStateHeader: "## \u5DE5\u4F5C\u72C0\u614B\uFF08\u5F9E\u5DE5\u5177\u8A18\u9304\u4E2D\u6A5F\u68B0\u63D0\u53D6\uFF09",
|
|
653
|
+
workingStateFiles: "\u5DF2\u5BEB\u5165/\u4FEE\u6539\u7684\u6A94\u6848\uFF08\u6700\u8FD1\u7684\u5728\u524D\uFF09\uFF1A",
|
|
654
|
+
workingStateCommands: "\u6700\u8FD1\u7684 shell \u547D\u4EE4\uFF1A",
|
|
655
|
+
workingStateTools: (list) => `\u58D3\u7E2E\u5340\u9593\u5167\u4F7F\u7528\u904E\u7684\u5DE5\u5177\uFF1A${list}`,
|
|
629
656
|
genCommitMessageInstructions: `\u4F60\u662F Git \u63D0\u4EA4\u8AAA\u660E\u751F\u6210\u52A9\u624B\u3002\u6839\u64DA\u7D66\u5B9A\u7684\u7A0B\u5F0F\u78BC\u5DEE\u7570\uFF0C\u751F\u6210\u4E00\u689D\u6E96\u78BA\u3001\u7C21\u6F54\u7684\u63D0\u4EA4\u8AAA\u660E\u3002
|
|
630
657
|
|
|
631
658
|
\u8981\u6C42\uFF1A
|
|
@@ -779,8 +806,17 @@ shell \u30B3\u30DE\u30F3\u30C9\u306B\u8907\u6570\u884C\u306E\u30B9\u30AF\u30EA\u
|
|
|
779
806
|
- \u30D5\u30A1\u30A4\u30EB\u306E\u5185\u5BB9\u5168\u4F53\u3092\u771F\u5B9F\u3068\u3057\u3066\u6271\u308F\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002\u3042\u308B\u30D5\u30A1\u30A4\u30EB\u304C\u8AAD\u307E\u308C\u305F\uFF0F\u7DE8\u96C6\u3055\u308C\u305F\u3068\u3044\u3046\u4E8B\u5B9F\u3060\u3051\u3092\u8A18\u9332\u3057\u307E\u3059\u3002\u5354\u50CD\u8005\u306F\u5185\u5BB9\u304C\u518D\u3073\u5FC5\u8981\u306B\u306A\u308C\u3070\u8AAD\u307F\u76F4\u3057\u307E\u3059\u3002\u53E4\u3044\u30D5\u30A1\u30A4\u30EB\u8A18\u61B6\u306F\u8A18\u61B6\u304C\u306A\u3044\u3088\u308A\u60AA\u3044\u3002
|
|
780
807
|
- \u524D\u56DE\u306E\u8981\u7D04\u304C\u63D0\u4F9B\u3055\u308C\u305F\u5834\u5408\uFF1A\u307E\u3060\u6709\u52B9\u306A\u7D50\u8AD6\u3060\u3051\u3092\u8A72\u5F53\u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u7D71\u5408\u3057\u3001\u5168\u4F53\u3092\u66F8\u304D\u76F4\u3057\u305F\u308A\u9805\u76EE\u3054\u3068\u306B\u8EE2\u8A18\u3057\u305F\u308A\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
781
808
|
- \u5177\u4F53\u7684\u306B\uFF1A\u30D1\u30B9\u3001\u540D\u524D\u3001\u30B3\u30DE\u30F3\u30C9\u3001id \u3092\u66F8\u304F\u3002\u66D6\u6627\u306A\u53C2\u7167\u306B\u3057\u306A\u3044\u3002
|
|
809
|
+
- \u8981\u7D04\u306F\u65E5\u672C\u8A9E\u3067\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002\u8981\u7D04\u306F\u4EE5\u964D\u306E\u6BCE\u30BF\u30FC\u30F3\u3067\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3068\u3068\u3082\u306B\u518D\u9001\u3055\u308C\u308B\u305F\u3081\u3001\u8A00\u8A9E\u304C\u98DF\u3044\u9055\u3046\u3068\u5354\u50CD\u8005\u304C\u5225\u306E\u8A00\u8A9E\u3067\u7B54\u3048\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002
|
|
782
810
|
- \u8981\u7D04\u30BB\u30AF\u30B7\u30E7\u30F3\u3060\u3051\u3092\u51FA\u529B\u3057\u3001\u524D\u7F6E\u304D\u3092\u4ED8\u3051\u306A\u3044\u3002`,
|
|
783
811
|
continuationContract: "\u524D\u56DE\u4E2D\u65AD\u3057\u305F\u3068\u3053\u308D\u304B\u3089\u7D9A\u3051\u3066\u304F\u3060\u3055\u3044\uFF1A\u8AAC\u660E\u3069\u304A\u308A\u306B\u73FE\u5728\u306E\u4F5C\u696D\u3068\u6B21\u306E\u624B\u9806\u3092\u5F15\u304D\u7D99\u304E\u307E\u3059\u3002\u65E2\u306B\u56DE\u7B54\u6E08\u307F\u306E\u8CEA\u554F\u3092\u7E70\u308A\u8FD4\u3055\u305A\u3001\u632F\u308A\u8FD4\u3089\u305A\u3001\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u304C\u5727\u7E2E\u3055\u308C\u305F\u3053\u3068\u306B\u3082\u89E6\u308C\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002\u4E0A\u8A18\u3067\u8A00\u53CA\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u306E\u5185\u5BB9\u304C\u5FC5\u8981\u306A\u5834\u5408\u306F\u3001\u3082\u3046\u4E00\u5EA6\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
812
|
+
compactedIntro: "\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u4EE5\u524D\u306E\u30BF\u30FC\u30F3\u306F\u5727\u7E2E\u3055\u308C\u307E\u3057\u305F\u3002\u4EE5\u4E0B\u306E\u8981\u7D04\u304C\u305D\u308C\u3089\u306E\u30BF\u30FC\u30F3\u306B\u3064\u3044\u3066\u306E\u3042\u306A\u305F\u306E\u8A18\u61B6\u3067\u3059\u3002",
|
|
813
|
+
compactedUserMessagesHeader: "## \u5727\u7E2E\u533A\u9593\u5185\u306E\u30E6\u30FC\u30B6\u30FC\u30E1\u30C3\u30BB\u30FC\u30B8\uFF08\u539F\u6587\u3001\u6642\u7CFB\u5217\uFF09",
|
|
814
|
+
compactedOmittedNote: (n) => `\uFF08\u4EE5\u524D\u306E\u30E6\u30FC\u30B6\u30FC\u30E1\u30C3\u30BB\u30FC\u30B8 ${n} \u4EF6\u306F\u7701\u7565\u3055\u308C\u307E\u3057\u305F \u2014 \u305D\u306E\u610F\u56F3\u306F\u4E0A\u8A18\u306E\u8981\u7D04\u306B\u542B\u307E\u308C\u3066\u3044\u307E\u3059\uFF09`,
|
|
815
|
+
compactedTrimmedNote: "\uFF08\u4EE5\u524D\u306E\u30BF\u30FC\u30F3\u306F\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u5236\u9650\u306B\u3088\u308A\u5207\u308A\u8A70\u3081\u3089\u308C\u3001\u8981\u7D04\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u4EE5\u524D\u306E\u7D50\u679C\u304C\u5FC5\u8981\u306A\u5834\u5408\u306F\u3001\u30D5\u30A1\u30A4\u30EB\u3092\u518D\u8AAD\u307F\u8FBC\u307F\u3059\u308B\u304B\u30B3\u30DE\u30F3\u30C9\u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\uFF09",
|
|
816
|
+
workingStateHeader: "## \u4F5C\u696D\u72B6\u614B\uFF08\u30C4\u30FC\u30EB\u8A18\u9332\u304B\u3089\u6A5F\u68B0\u7684\u306B\u62BD\u51FA\uFF09",
|
|
817
|
+
workingStateFiles: "\u66F8\u304D\u8FBC\u307F/\u7DE8\u96C6\u3057\u305F\u30D5\u30A1\u30A4\u30EB\uFF08\u65B0\u3057\u3044\u9806\uFF09\uFF1A",
|
|
818
|
+
workingStateCommands: "\u6700\u8FD1\u306E\u30B7\u30A7\u30EB\u30B3\u30DE\u30F3\u30C9\uFF1A",
|
|
819
|
+
workingStateTools: (list) => `\u5727\u7E2E\u533A\u9593\u5185\u3067\u4F7F\u7528\u3057\u305F\u30C4\u30FC\u30EB\uFF1A${list}`,
|
|
784
820
|
genCommitMessageInstructions: `\u3042\u306A\u305F\u306F Git \u30B3\u30DF\u30C3\u30C8\u30E1\u30C3\u30BB\u30FC\u30B8\u751F\u6210\u30A2\u30B7\u30B9\u30BF\u30F3\u30C8\u3067\u3059\u3002\u4E0E\u3048\u3089\u308C\u305F\u30B3\u30FC\u30C9\u5DEE\u5206\u304B\u3089\u3001\u6B63\u78BA\u3067\u7C21\u6F54\u306A\u30B3\u30DF\u30C3\u30C8\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u751F\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
785
821
|
|
|
786
822
|
\u8981\u4EF6\uFF1A
|
|
@@ -934,8 +970,17 @@ shell \uBA85\uB839\uC5D0 \uC5EC\uB7EC \uC904 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC7
|
|
|
934
970
|
- \uD30C\uC77C \uB0B4\uC6A9 \uC804\uCCB4\uB97C \uC9C4\uC2E4\uB85C \uCDE8\uAE09\uD558\uC9C0 \uB9C8\uC138\uC694. \uC5B4\uB5A4 \uD30C\uC77C\uC774 \uC77D\uD788\uAC70\uB098 \uD3B8\uC9D1\uB418\uC5C8\uB2E4\uB294 \uC0AC\uC2E4\uB9CC \uAE30\uB85D\uD569\uB2C8\uB2E4. \uD611\uC5C5\uC790\uB294 \uB0B4\uC6A9\uC774 \uB2E4\uC2DC \uD544\uC694\uD558\uBA74 \uB2E4\uC2DC \uC77D\uC2B5\uB2C8\uB2E4. \uC624\uB798\uB41C \uD30C\uC77C \uAE30\uC5B5\uC740 \uAE30\uC5B5\uC774 \uC5C6\uB294 \uAC83\uBCF4\uB2E4 \uB098\uC069\uB2C8\uB2E4.
|
|
935
971
|
- \uC774\uC804 \uC694\uC57D\uC774 \uC81C\uACF5\uB418\uC5C8\uB2E4\uBA74: \uC5EC\uC804\uD788 \uC720\uD6A8\uD55C \uACB0\uB860\uB9CC \uD574\uB2F9 \uC139\uC158\uC5D0 \uBCD1\uD569\uD558\uACE0, \uC804\uCCB4\uB97C \uB2E4\uC2DC \uC4F0\uAC70\uB098 \uD56D\uBAA9\uBCC4\uB85C \uC62E\uACA8 \uC801\uC9C0 \uB9C8\uC138\uC694.
|
|
936
972
|
- \uAD6C\uCCB4\uC801\uC73C\uB85C: \uACBD\uB85C, \uC774\uB984, \uBA85\uB839, id\uB97C \uC4F8 \uAC83. \uBAA8\uD638\uD55C \uCC38\uC870\uB294 \uAE08\uC9C0.
|
|
973
|
+
- \uC694\uC57D\uC740 \uD55C\uAD6D\uC5B4\uB85C \uC791\uC131\uD558\uC138\uC694. \uC694\uC57D\uC740 \uC774\uD6C4 \uB9E4 \uD134\uB9C8\uB2E4 \uCEE8\uD14D\uC2A4\uD2B8\uC640 \uD568\uAED8 \uB2E4\uC2DC \uC804\uC1A1\uB418\uBBC0\uB85C, \uC5B8\uC5B4\uAC00 \uC5B4\uAE0B\uB098\uBA74 \uD611\uC5C5\uC790\uAC00 \uB2E4\uB978 \uC5B8\uC5B4\uB85C \uB2F5\uD558\uAC8C \uB429\uB2C8\uB2E4.
|
|
937
974
|
- \uC694\uC57D \uC139\uC158\uB9CC \uCD9C\uB825\uD558\uACE0 \uC11C\uB450\uB97C \uBD99\uC774\uC9C0 \uB9C8\uC138\uC694.`,
|
|
938
975
|
continuationContract: "\uC911\uB2E8\uD55C \uC9C0\uC810\uBD80\uD130 \uC774\uC5B4\uAC00\uC138\uC694: \uC124\uBA85\uD55C \uB300\uB85C \uD604\uC7AC \uC791\uC5C5\uACFC \uB2E4\uC74C \uB2E8\uACC4\uB97C \uADF8\uB300\uB85C \uC774\uC5B4\uBC1B\uC2B5\uB2C8\uB2E4. \uC774\uBBF8 \uB2F5\uD55C \uC9C8\uBB38\uC744 \uB2E4\uC2DC \uBB3B\uC9C0 \uB9D0\uACE0, \uB418\uB3CC\uC544\uBCF4\uC9C0 \uB9D0\uACE0, \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uC555\uCD95\uB418\uC5C8\uB2E4\uB294 \uC0AC\uC2E4\uB3C4 \uC5B8\uAE09\uD558\uC9C0 \uB9C8\uC138\uC694. \uC704\uC5D0\uC11C \uC5B8\uAE09\uD55C \uD30C\uC77C\uC758 \uB0B4\uC6A9\uC774 \uD544\uC694\uD558\uBA74 \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.",
|
|
976
|
+
compactedIntro: "\uC774 \uC138\uC158\uC758 \uC774\uC804 \uD134\uC740 \uC555\uCD95\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC544\uB798 \uC694\uC57D\uC774 \uADF8 \uD134\uB4E4\uC5D0 \uB300\uD55C \uB2F9\uC2E0\uC758 \uAE30\uC5B5\uC785\uB2C8\uB2E4.",
|
|
977
|
+
compactedUserMessagesHeader: "## \uC555\uCD95 \uAD6C\uAC04\uC758 \uC0AC\uC6A9\uC790 \uBA54\uC2DC\uC9C0 (\uC6D0\uBB38, \uC2DC\uAC04 \uC21C)",
|
|
978
|
+
compactedOmittedNote: (n) => `(\uC774\uC804 \uC0AC\uC6A9\uC790 \uBA54\uC2DC\uC9C0 ${n}\uAC1C\uB294 \uC0DD\uB7B5\uB428 \u2014 \uADF8 \uC758\uB3C4\uB294 \uC704 \uC694\uC57D\uC5D0 \uD3EC\uD568\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4)`,
|
|
979
|
+
compactedTrimmedNote: "(\uC774\uC804 \uD134\uC740 \uCEE8\uD14D\uC2A4\uD2B8 \uC708\uB3C4 \uC81C\uD55C\uC73C\uB85C \uC798\uB838\uC73C\uBA70 \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC694\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uC804 \uACB0\uACFC\uAC00 \uD544\uC694\uD558\uBA74 \uD30C\uC77C\uC744 \uB2E4\uC2DC \uC77D\uAC70\uB098 \uBA85\uB839\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.)",
|
|
980
|
+
workingStateHeader: "## \uC791\uC5C5 \uC0C1\uD0DC (\uB3C4\uAD6C \uAE30\uB85D\uC5D0\uC11C \uAE30\uACC4\uC801\uC73C\uB85C \uCD94\uCD9C)",
|
|
981
|
+
workingStateFiles: "\uC791\uC131/\uC218\uC815\uD55C \uD30C\uC77C (\uCD5C\uADFC \uC21C):",
|
|
982
|
+
workingStateCommands: "\uCD5C\uADFC \uC178 \uBA85\uB839:",
|
|
983
|
+
workingStateTools: (list) => `\uC555\uCD95 \uAD6C\uAC04\uC5D0\uC11C \uC0AC\uC6A9\uD55C \uB3C4\uAD6C: ${list}`,
|
|
939
984
|
genCommitMessageInstructions: `\uB2F9\uC2E0\uC740 Git \uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uC0DD\uC131 \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC785\uB2C8\uB2E4. \uC8FC\uC5B4\uC9C4 \uCF54\uB4DC \uCC28\uC774\uB85C \uC815\uD655\uD558\uACE0 \uAC04\uACB0\uD55C \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB97C \uC0DD\uC131\uD558\uC138\uC694.
|
|
940
985
|
|
|
941
986
|
\uC694\uAD6C \uC0AC\uD56D:
|
|
@@ -1089,8 +1134,17 @@ Reglas:
|
|
|
1089
1134
|
- No trates el contenido completo de un archivo como verdad. Registra solo el hecho de que un archivo se ley\xF3 o edit\xF3; el colaborador volver\xE1 a leerlo si necesita el contenido. Una memoria obsoleta de un archivo es peor que no tener memoria.
|
|
1090
1135
|
- Si se proporciona un resumen anterior: integra solo sus conclusiones a\xFAn v\xE1lidas en las secciones correspondientes; no lo repitas entero ni lo copies entrada por entrada.
|
|
1091
1136
|
- S\xE9 concreto: rutas, nombres, comandos, ids, no referencias vagas.
|
|
1137
|
+
- Escribe el resumen en espa\xF1ol. Se reenv\xEDa con el contexto en cada turno posterior; una diferencia de idioma hace que el colaborador responda en otro idioma.
|
|
1092
1138
|
- Devuelve solo las secciones del resumen, sin pre\xE1mbulo.`,
|
|
1093
1139
|
continuationContract: "Contin\xFAa donde lo dejaste: retoma el trabajo actual y el siguiente paso exactamente como se describe. No vuelvas a preguntar lo que ya se respondi\xF3, no recapitules y no menciones que el contexto se ha compactado. Si necesitas el contenido de alg\xFAn archivo mencionado arriba, vuelve a leerlo.",
|
|
1140
|
+
compactedIntro: "Los turnos anteriores de esta sesi\xF3n se compactaron. El resumen de abajo es tu memoria de ellos.",
|
|
1141
|
+
compactedUserMessagesHeader: "## Mensajes del usuario en el tramo compactado (textual, cronol\xF3gico)",
|
|
1142
|
+
compactedOmittedNote: (n) => `(${n} mensajes anteriores del usuario omitidos \u2014 su intenci\xF3n est\xE1 cubierta por el resumen de arriba)`,
|
|
1143
|
+
compactedTrimmedNote: "(Los turnos anteriores se recortaron para ajustarse a la ventana de contexto; no hay resumen disponible. Vuelve a leer archivos y reejecuta comandos si necesitas resultados previos.)",
|
|
1144
|
+
workingStateHeader: "## Estado de trabajo (extra\xEDdo mec\xE1nicamente de los registros de herramientas)",
|
|
1145
|
+
workingStateFiles: "Archivos escritos/editados (m\xE1s recientes primero):",
|
|
1146
|
+
workingStateCommands: "Comandos de shell recientes:",
|
|
1147
|
+
workingStateTools: (list) => `Herramientas usadas en el tramo resumido: ${list}`,
|
|
1094
1148
|
genCommitMessageInstructions: `Eres un asistente de mensajes de commit de Git. Dado un diff de c\xF3digo, produce un mensaje de commit preciso y conciso.
|
|
1095
1149
|
|
|
1096
1150
|
Requisitos:
|
|
@@ -1347,7 +1401,7 @@ function pickBoundary(messages, keepTokens) {
|
|
|
1347
1401
|
return boundary;
|
|
1348
1402
|
}
|
|
1349
1403
|
var WRITE_HINTS = ["write", "edit", "append", "save", "create", "patch"];
|
|
1350
|
-
function extractWorkingState(span) {
|
|
1404
|
+
function extractWorkingState(span, lang) {
|
|
1351
1405
|
const files = [];
|
|
1352
1406
|
const commands = [];
|
|
1353
1407
|
const tools = /* @__PURE__ */ new Set();
|
|
@@ -1390,23 +1444,20 @@ function extractWorkingState(span) {
|
|
|
1390
1444
|
}
|
|
1391
1445
|
return seen;
|
|
1392
1446
|
};
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1395
|
-
];
|
|
1447
|
+
const p = getPrompts(lang);
|
|
1448
|
+
const lines = [p.workingStateHeader];
|
|
1396
1449
|
const written = dedupe(files, 20);
|
|
1397
1450
|
if (written.length) {
|
|
1398
|
-
lines.push(
|
|
1451
|
+
lines.push(p.workingStateFiles);
|
|
1399
1452
|
lines.push(...written.map((f) => `- ${f}`));
|
|
1400
1453
|
}
|
|
1401
1454
|
const recentCmds = commands.slice(-10);
|
|
1402
1455
|
if (recentCmds.length) {
|
|
1403
|
-
lines.push(
|
|
1456
|
+
lines.push(p.workingStateCommands);
|
|
1404
1457
|
lines.push(...recentCmds.map((c) => `- ${c}`));
|
|
1405
1458
|
}
|
|
1406
1459
|
if (tools.size) {
|
|
1407
|
-
lines.push(
|
|
1408
|
-
"Tools used in the summarized span: " + [...tools].sort().join(", ")
|
|
1409
|
-
);
|
|
1460
|
+
lines.push(p.workingStateTools([...tools].sort().join(", ")));
|
|
1410
1461
|
}
|
|
1411
1462
|
return lines.length > 1 ? lines.join("\n") : "";
|
|
1412
1463
|
}
|
|
@@ -1530,7 +1581,7 @@ async function buildState(messages, provider, model, keepTokens, prior = null, o
|
|
|
1530
1581
|
return {
|
|
1531
1582
|
boundaryIndex: boundary,
|
|
1532
1583
|
summaryText: summary,
|
|
1533
|
-
workingState: extractWorkingState(span),
|
|
1584
|
+
workingState: extractWorkingState(span, lang),
|
|
1534
1585
|
userMessages: cappedUsers,
|
|
1535
1586
|
userMessagesDropped: dropped,
|
|
1536
1587
|
createdAt: Date.now(),
|
|
@@ -1538,7 +1589,7 @@ async function buildState(messages, provider, model, keepTokens, prior = null, o
|
|
|
1538
1589
|
trimmed: false
|
|
1539
1590
|
};
|
|
1540
1591
|
}
|
|
1541
|
-
function trimState(messages, prior = null, fraction = TRIM_FRACTION) {
|
|
1592
|
+
function trimState(messages, prior = null, fraction = TRIM_FRACTION, lang) {
|
|
1542
1593
|
const start = prior?.boundaryIndex ?? 0;
|
|
1543
1594
|
const remaining = messages.length - start;
|
|
1544
1595
|
if (remaining <= 2) return null;
|
|
@@ -1556,7 +1607,7 @@ function trimState(messages, prior = null, fraction = TRIM_FRACTION) {
|
|
|
1556
1607
|
const span = messages.slice(start, boundary);
|
|
1557
1608
|
const priorUsers = prior?.userMessages ? [...prior.userMessages] : [];
|
|
1558
1609
|
const priorSummary = prior?.summaryText ?? "";
|
|
1559
|
-
const summary = (priorSummary ? priorSummary + "\n\n" : "") +
|
|
1610
|
+
const summary = (priorSummary ? priorSummary + "\n\n" : "") + getPrompts(lang).compactedTrimmedNote;
|
|
1560
1611
|
const allUsers = [...priorUsers, ...extractUserMessages(span)];
|
|
1561
1612
|
const { messages: cappedUsers, dropped } = capUserMessages(
|
|
1562
1613
|
allUsers,
|
|
@@ -1565,7 +1616,7 @@ function trimState(messages, prior = null, fraction = TRIM_FRACTION) {
|
|
|
1565
1616
|
return {
|
|
1566
1617
|
boundaryIndex: boundary,
|
|
1567
1618
|
summaryText: summary,
|
|
1568
|
-
workingState: extractWorkingState(span),
|
|
1619
|
+
workingState: extractWorkingState(span, lang),
|
|
1569
1620
|
userMessages: cappedUsers,
|
|
1570
1621
|
userMessagesDropped: dropped,
|
|
1571
1622
|
createdAt: Date.now(),
|
|
@@ -1576,7 +1627,7 @@ function trimState(messages, prior = null, fraction = TRIM_FRACTION) {
|
|
|
1576
1627
|
function compactedBlock(state, lang) {
|
|
1577
1628
|
const parts = [
|
|
1578
1629
|
"<compacted-history>",
|
|
1579
|
-
|
|
1630
|
+
getPrompts(lang).compactedIntro,
|
|
1580
1631
|
"",
|
|
1581
1632
|
state.summaryText
|
|
1582
1633
|
];
|
|
@@ -1586,12 +1637,10 @@ function compactedBlock(state, lang) {
|
|
|
1586
1637
|
if (state.userMessages.length > 0) {
|
|
1587
1638
|
parts.push(
|
|
1588
1639
|
"",
|
|
1589
|
-
|
|
1640
|
+
getPrompts(lang).compactedUserMessagesHeader
|
|
1590
1641
|
);
|
|
1591
1642
|
if (state.userMessagesDropped > 0) {
|
|
1592
|
-
parts.push(
|
|
1593
|
-
`(${state.userMessagesDropped} earlier user messages omitted \u2014 their intent is covered by the summary above)`
|
|
1594
|
-
);
|
|
1643
|
+
parts.push(getPrompts(lang).compactedOmittedNote(state.userMessagesDropped));
|
|
1595
1644
|
}
|
|
1596
1645
|
parts.push(...state.userMessages.map((u) => `- ${u}`));
|
|
1597
1646
|
}
|
|
@@ -1693,12 +1742,12 @@ var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1693
1742
|
]);
|
|
1694
1743
|
function parseReadFileSpan(content) {
|
|
1695
1744
|
const body = content.replace(/^\[tool output truncated:[^\n]*\]\n\n/, "");
|
|
1696
|
-
let
|
|
1745
|
+
let path13;
|
|
1697
1746
|
let start;
|
|
1698
1747
|
let end;
|
|
1699
1748
|
try {
|
|
1700
1749
|
const obj = JSON.parse(body);
|
|
1701
|
-
|
|
1750
|
+
path13 = obj.path;
|
|
1702
1751
|
start = obj.start_line;
|
|
1703
1752
|
end = obj.end_line;
|
|
1704
1753
|
} catch {
|
|
@@ -1707,14 +1756,14 @@ function parseReadFileSpan(content) {
|
|
|
1707
1756
|
const m = new RegExp(`"${key}"\\s*:\\s*(\\d+)`).exec(body);
|
|
1708
1757
|
return m ? Number(m[1]) : void 0;
|
|
1709
1758
|
};
|
|
1710
|
-
|
|
1759
|
+
path13 = str("path");
|
|
1711
1760
|
start = num("start_line");
|
|
1712
1761
|
end = num("end_line");
|
|
1713
1762
|
}
|
|
1714
|
-
if (typeof
|
|
1763
|
+
if (typeof path13 !== "string" || !path13) return null;
|
|
1715
1764
|
if (typeof start !== "number" || typeof end !== "number") return null;
|
|
1716
1765
|
if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
|
|
1717
|
-
return { path:
|
|
1766
|
+
return { path: path13, start, end };
|
|
1718
1767
|
}
|
|
1719
1768
|
function addSpan(spans, start, end) {
|
|
1720
1769
|
spans.push([start, end]);
|
|
@@ -1771,16 +1820,45 @@ function applyReadFileDedup(messages) {
|
|
|
1771
1820
|
}
|
|
1772
1821
|
var OVERFLOW_MARKERS = [
|
|
1773
1822
|
"context_length_exceeded",
|
|
1774
|
-
"
|
|
1823
|
+
"context length",
|
|
1775
1824
|
"context window",
|
|
1776
1825
|
"prompt is too long",
|
|
1777
1826
|
"input is too long",
|
|
1778
1827
|
"too many tokens",
|
|
1779
1828
|
"input length and `max_tokens` exceed",
|
|
1780
|
-
"exceeds the maximum number of tokens"
|
|
1829
|
+
"exceeds the maximum number of tokens",
|
|
1830
|
+
"\u8D85\u51FA\u6A21\u578B\u4E0A\u4E0B\u6587",
|
|
1831
|
+
"\u8D85\u8FC7\u6A21\u578B\u4E0A\u4E0B\u6587",
|
|
1832
|
+
"\u8D85\u904E\u6A21\u578B\u4E0A\u4E0B\u6587",
|
|
1833
|
+
"\u4E0A\u4E0B\u6587\u957F\u5EA6\u8D85\u8FC7",
|
|
1834
|
+
"\u8D85\u8FC7\u6700\u5927\u4E0A\u4E0B\u6587",
|
|
1835
|
+
"\u8D85\u904E\u6700\u5927\u4E0A\u4E0B\u6587",
|
|
1836
|
+
"\u4E0A\u4E0B\u6587\u8D85\u9650",
|
|
1837
|
+
"\u8F93\u5165\u8FC7\u957F"
|
|
1781
1838
|
];
|
|
1839
|
+
function overflowText(exc) {
|
|
1840
|
+
const parts = [];
|
|
1841
|
+
const push = (v) => {
|
|
1842
|
+
if (typeof v === "string" && v) parts.push(v);
|
|
1843
|
+
};
|
|
1844
|
+
push(String(exc));
|
|
1845
|
+
if (exc && typeof exc === "object") {
|
|
1846
|
+
const rec = exc;
|
|
1847
|
+
push(rec["message"]);
|
|
1848
|
+
push(rec["detail"]);
|
|
1849
|
+
const body = rec["error"];
|
|
1850
|
+
if (body && typeof body === "object") {
|
|
1851
|
+
const b = body;
|
|
1852
|
+
push(b["message"]);
|
|
1853
|
+
push(b["code"]);
|
|
1854
|
+
} else {
|
|
1855
|
+
push(body);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
return parts.join(" ").toLowerCase();
|
|
1859
|
+
}
|
|
1782
1860
|
function isContextOverflow(exc) {
|
|
1783
|
-
const text =
|
|
1861
|
+
const text = overflowText(exc);
|
|
1784
1862
|
return OVERFLOW_MARKERS.some((m) => text.includes(m));
|
|
1785
1863
|
}
|
|
1786
1864
|
|
|
@@ -1813,6 +1891,9 @@ var TOOL_MAX_CHARS = {
|
|
|
1813
1891
|
web_search: 8e3,
|
|
1814
1892
|
list_files: 8e3,
|
|
1815
1893
|
shell_task_output: 8e3,
|
|
1894
|
+
/* repo_map 自带 16K 上限(tools/repoMap.ts 的 MAX_CHARS)。这里显式登记,
|
|
1895
|
+
* 而不是落到 24K 默认值 —— 免得将来工具上限调大时被二次裁剪,口径也保持一致。 */
|
|
1896
|
+
repo_map: 16e3,
|
|
1816
1897
|
git_log: 6e3,
|
|
1817
1898
|
git_status: 4e3
|
|
1818
1899
|
};
|
|
@@ -2122,6 +2203,7 @@ var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
2122
2203
|
var MAX_COMPACT_ROUNDS = 4;
|
|
2123
2204
|
var OVERFLOW_TARGET_RATIO = 0.5;
|
|
2124
2205
|
var OVERFLOW_TRIM_FRACTION = 0.5;
|
|
2206
|
+
var OVERFLOW_ELIDE_KEEP_FRACTION = 0.02;
|
|
2125
2207
|
var COMPACT_STALL_RETRY_DELTA = 20;
|
|
2126
2208
|
var FINALIZE_ON_LIMIT_PROMPT = "\u5DF2\u8FBE\u5230\u672C\u8F6E\u8FED\u4EE3\u4E0A\u9650\uFF0C\u4F60\u4E0D\u80FD\u518D\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\u3002\u8BF7\u7ACB\u5373\u57FA\u4E8E\u4E0A\u9762\u5DF2\u7ECF\u6536\u96C6\u5230\u7684\u4FE1\u606F\u8F93\u51FA\u6700\u7EC8\u62A5\u544A\uFF1A\u76F4\u63A5\u56DE\u7B54\u4EFB\u52A1\u3001\u7ED9\u51FA\u7ED3\u8BBA\u4E0E path:line \u5F15\u7528\uFF0C\u5E76\u660E\u786E\u8BF4\u660E\u54EA\u4E9B\u90E8\u5206\u5C1A\u672A\u67E5\u8BC1\u3002\u4E0D\u8981\u8BE2\u95EE\u3001\u4E0D\u8981\u7EE7\u7EED\u63A2\u7D22\u3002";
|
|
2127
2209
|
function toolResultMessage(tc, result, taskId, toolResultDir2) {
|
|
@@ -2250,6 +2332,8 @@ var TurnEngine = class _TurnEngine {
|
|
|
2250
2332
|
_lastContextTokens = null;
|
|
2251
2333
|
/** 压缩无进展时的消息条数快照;-1 表示无冷却 */
|
|
2252
2334
|
_compactStalledAt = -1;
|
|
2335
|
+
/** 溢出兜底:已 400 时无条件淘汰旧工具结果(下一次成功调用后复位) */
|
|
2336
|
+
_overflowElide = false;
|
|
2253
2337
|
/** 显式配置的上下文窗口大小(token 数),未设置时为 undefined(走自动检测) */
|
|
2254
2338
|
_contextWindow;
|
|
2255
2339
|
/** 压缩触发阈值比例(默认 0.8) */
|
|
@@ -2388,11 +2472,12 @@ ${notice}` : text,
|
|
|
2388
2472
|
};
|
|
2389
2473
|
}
|
|
2390
2474
|
/** 排队 steering 消息(下一迭代间隙注入为 user 消息) */
|
|
2391
|
-
queueSteering(text, attachments, attachmentRefs) {
|
|
2475
|
+
queueSteering(text, attachments, attachmentRefs, actor) {
|
|
2392
2476
|
this._steering.push({
|
|
2393
2477
|
text,
|
|
2394
2478
|
...attachments?.length ? { attachments } : {},
|
|
2395
|
-
...attachmentRefs?.length ? { attachmentRefs } : {}
|
|
2479
|
+
...attachmentRefs?.length ? { attachmentRefs } : {},
|
|
2480
|
+
...actor ? { actor } : {}
|
|
2396
2481
|
});
|
|
2397
2482
|
}
|
|
2398
2483
|
/**
|
|
@@ -2417,7 +2502,7 @@ ${notice}` : text,
|
|
|
2417
2502
|
* 追加用户输入到历史,产出 TURN_START 事件,然后转发 _loop()
|
|
2418
2503
|
* 的全部事件。收到中断后仍会消费完剩余事件(保证 TURN_END 产出)。
|
|
2419
2504
|
*/
|
|
2420
|
-
async *run(userInput, taskId, attachments, attachmentRefs) {
|
|
2505
|
+
async *run(userInput, taskId, attachments, attachmentRefs, actor) {
|
|
2421
2506
|
if (!this.model.trim()) {
|
|
2422
2507
|
throw new Error(
|
|
2423
2508
|
"\u672A\u6307\u5B9A\u6A21\u578B\uFF1A\u8BF7\u5148\u9009\u62E9\u6A21\u578B\uFF08CLI \u8FD0\u884C /connect\uFF1B\u63A7\u5236\u53F0\u5728\u300C\u8BBE\u7F6E \u2192 AI \u6A21\u578B\u300D\u4E2D\u6DFB\u52A0\u4F9B\u5E94\u5546\u5E76\u9009\u62E9\u6A21\u578B\uFF09"
|
|
@@ -2440,12 +2525,15 @@ ${notice}` : text,
|
|
|
2440
2525
|
this._cancel = false;
|
|
2441
2526
|
this._producedFiles = [];
|
|
2442
2527
|
this._compactStalledAt = -1;
|
|
2528
|
+
this._overflowElide = false;
|
|
2443
2529
|
this._emitHook((h) => h.onTurnStart?.(userInput));
|
|
2444
2530
|
yield {
|
|
2445
2531
|
type: "turn_start" /* TURN_START */,
|
|
2446
2532
|
data: {
|
|
2447
2533
|
taskId: this.taskId,
|
|
2448
2534
|
input: userInput,
|
|
2535
|
+
// 谁发起的本轮:会话详情据此标注(本地/旧网关没有该字段)
|
|
2536
|
+
...actor ? { actor } : {},
|
|
2449
2537
|
// 只报个数:附件字节不进事件流(事件会落盘,base64 会把日志撑爆)
|
|
2450
2538
|
...attachments?.length ? { attachmentCount: attachments.length } : {},
|
|
2451
2539
|
// 落盘引用足够小,随事件带给控制台渲染缩略图 / 详情回看
|
|
@@ -2749,6 +2837,12 @@ ${notice}` : text,
|
|
|
2749
2837
|
type: "compacting" /* COMPACTING */,
|
|
2750
2838
|
data: { taskId: this.taskId, ...startInfo }
|
|
2751
2839
|
};
|
|
2840
|
+
let elided = false;
|
|
2841
|
+
if (this._elisionEnabled) {
|
|
2842
|
+
const before = this._estimateContextTokens();
|
|
2843
|
+
this._overflowElide = true;
|
|
2844
|
+
elided = this._estimateContextTokens() < before;
|
|
2845
|
+
}
|
|
2752
2846
|
const result = await this._compactNow(overflowReqId, true);
|
|
2753
2847
|
if (result.notice) {
|
|
2754
2848
|
const notice = result.notice;
|
|
@@ -2787,6 +2881,11 @@ ${notice}` : text,
|
|
|
2787
2881
|
}
|
|
2788
2882
|
continue;
|
|
2789
2883
|
}
|
|
2884
|
+
if (elided) {
|
|
2885
|
+
this._appendNotice("compacted", "\u4E0A\u4E0B\u6587\u6EA2\u51FA \u2014 \u5DF2\u6DD8\u6C70\u65E7\u5DE5\u5177\u7ED3\u679C\u540E\u91CD\u8BD5");
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
this._overflowElide = false;
|
|
2790
2889
|
}
|
|
2791
2890
|
if (!this._cancel && !streamed && isTransientNetworkError(exc) && netRetries < netMax) {
|
|
2792
2891
|
netRetries++;
|
|
@@ -2857,6 +2956,7 @@ ${notice}` : text,
|
|
|
2857
2956
|
return;
|
|
2858
2957
|
}
|
|
2859
2958
|
netRetries = 0;
|
|
2959
|
+
this._overflowElide = false;
|
|
2860
2960
|
if (this._cancel && turn === null) {
|
|
2861
2961
|
yield* this._finishInterrupted({
|
|
2862
2962
|
iterations,
|
|
@@ -2915,6 +3015,7 @@ ${notice}` : text,
|
|
|
2915
3015
|
data: {
|
|
2916
3016
|
text: s.text,
|
|
2917
3017
|
taskId: this.taskId,
|
|
3018
|
+
...s.actor ? { actor: s.actor } : {},
|
|
2918
3019
|
...s.attachmentRefs?.length ? { attachments: s.attachmentRefs } : {}
|
|
2919
3020
|
}
|
|
2920
3021
|
};
|
|
@@ -2979,6 +3080,7 @@ ${notice}` : text,
|
|
|
2979
3080
|
data: {
|
|
2980
3081
|
text: s.text,
|
|
2981
3082
|
taskId: this.taskId,
|
|
3083
|
+
...s.actor ? { actor: s.actor } : {},
|
|
2982
3084
|
...s.attachmentRefs?.length ? { attachments: s.attachmentRefs } : {}
|
|
2983
3085
|
}
|
|
2984
3086
|
};
|
|
@@ -3403,13 +3505,14 @@ ${notice}` : text,
|
|
|
3403
3505
|
const deduped = this._dedupEnabled ? applyReadFileDedup(base).messages : base;
|
|
3404
3506
|
let view = this._finalizeOutbound(deduped);
|
|
3405
3507
|
if (!this._elisionEnabled) return view;
|
|
3406
|
-
|
|
3508
|
+
const soft = this._softTriggerTokens();
|
|
3509
|
+
if (!this._overflowElide && estimateTokens(view) < soft) {
|
|
3407
3510
|
return view;
|
|
3408
3511
|
}
|
|
3409
3512
|
const oneShot = applyOneShotElision(deduped);
|
|
3410
3513
|
if (oneShot.freedChars > 0) {
|
|
3411
3514
|
view = this._finalizeOutbound(oneShot.messages);
|
|
3412
|
-
if (estimateTokens(view) <
|
|
3515
|
+
if (!this._overflowElide && estimateTokens(view) < soft) {
|
|
3413
3516
|
return view;
|
|
3414
3517
|
}
|
|
3415
3518
|
}
|
|
@@ -3418,7 +3521,8 @@ ${notice}` : text,
|
|
|
3418
3521
|
this._getContextWindow(),
|
|
3419
3522
|
this._thresholdPct,
|
|
3420
3523
|
this._capTokens
|
|
3421
|
-
)
|
|
3524
|
+
),
|
|
3525
|
+
this._overflowElide ? OVERFLOW_ELIDE_KEEP_FRACTION : ELIDE_KEEP_FRACTION
|
|
3422
3526
|
);
|
|
3423
3527
|
const elided = applyToolResultElision(
|
|
3424
3528
|
oneShot.messages,
|
|
@@ -3617,7 +3721,8 @@ ${notice}` : text,
|
|
|
3617
3721
|
const trimmed = trimState(
|
|
3618
3722
|
this.messages,
|
|
3619
3723
|
this.compactionState,
|
|
3620
|
-
force ? OVERFLOW_TRIM_FRACTION : 0.25
|
|
3724
|
+
force ? OVERFLOW_TRIM_FRACTION : 0.25,
|
|
3725
|
+
this.lang
|
|
3621
3726
|
);
|
|
3622
3727
|
if (!trimmed) break;
|
|
3623
3728
|
this.compactionState = trimmed;
|
|
@@ -3662,9 +3767,9 @@ ${notice}` : text,
|
|
|
3662
3767
|
return;
|
|
3663
3768
|
}
|
|
3664
3769
|
if (result && typeof result === "object") {
|
|
3665
|
-
const
|
|
3666
|
-
if (
|
|
3667
|
-
this._producedFiles.push(
|
|
3770
|
+
const path13 = result.path;
|
|
3771
|
+
if (path13) {
|
|
3772
|
+
this._producedFiles.push(path13);
|
|
3668
3773
|
return;
|
|
3669
3774
|
}
|
|
3670
3775
|
const changed = result.changed_files;
|
|
@@ -4203,62 +4308,196 @@ var PermissionEngine = class {
|
|
|
4203
4308
|
};
|
|
4204
4309
|
|
|
4205
4310
|
// src/tools/files.ts
|
|
4311
|
+
import * as fs6 from "fs";
|
|
4312
|
+
import * as path8 from "path";
|
|
4313
|
+
import { createHash } from "crypto";
|
|
4314
|
+
import { StringDecoder } from "string_decoder";
|
|
4315
|
+
|
|
4316
|
+
// src/tools/ignore.ts
|
|
4206
4317
|
import * as fs5 from "fs";
|
|
4207
4318
|
import * as path7 from "path";
|
|
4319
|
+
var ALWAYS_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
4320
|
+
// JS / TS
|
|
4321
|
+
"node_modules",
|
|
4322
|
+
"dist",
|
|
4323
|
+
"build",
|
|
4324
|
+
"out",
|
|
4325
|
+
".next",
|
|
4326
|
+
".nuxt",
|
|
4327
|
+
".cache",
|
|
4328
|
+
// JVM
|
|
4329
|
+
"target",
|
|
4330
|
+
".gradle",
|
|
4331
|
+
".mvn",
|
|
4332
|
+
// .NET
|
|
4333
|
+
"bin",
|
|
4334
|
+
"obj",
|
|
4335
|
+
".vs",
|
|
4336
|
+
"TestResults",
|
|
4337
|
+
// Python / Ruby / PHP
|
|
4338
|
+
"__pycache__",
|
|
4339
|
+
".venv",
|
|
4340
|
+
"venv",
|
|
4341
|
+
".pytest_cache",
|
|
4342
|
+
".mypy_cache",
|
|
4343
|
+
"vendor",
|
|
4344
|
+
// 移动端
|
|
4345
|
+
"Pods",
|
|
4346
|
+
".dart_tool",
|
|
4347
|
+
"DerivedData",
|
|
4348
|
+
// 覆盖率 / 通用
|
|
4349
|
+
"coverage",
|
|
4350
|
+
// 版本库
|
|
4351
|
+
".git",
|
|
4352
|
+
".svn",
|
|
4353
|
+
".hg"
|
|
4354
|
+
]);
|
|
4355
|
+
function loadGitignore(dir) {
|
|
4356
|
+
const file = path7.join(dir, ".gitignore");
|
|
4357
|
+
let text;
|
|
4358
|
+
try {
|
|
4359
|
+
const stat = fs5.statSync(file);
|
|
4360
|
+
if (stat.size > 64 * 1024) return [];
|
|
4361
|
+
text = fs5.readFileSync(file, "utf-8");
|
|
4362
|
+
} catch {
|
|
4363
|
+
return [];
|
|
4364
|
+
}
|
|
4365
|
+
const matchers = [];
|
|
4366
|
+
for (const rawLine of text.split("\n")) {
|
|
4367
|
+
let line = rawLine.replace(/\r$/, "").trim();
|
|
4368
|
+
if (!line || line.startsWith("#")) continue;
|
|
4369
|
+
if (line.startsWith("!")) continue;
|
|
4370
|
+
const anchored = rawLine.trim().startsWith("/");
|
|
4371
|
+
const dirOnly = /\/\s*$/.test(rawLine.trim());
|
|
4372
|
+
line = line.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
4373
|
+
if (!line) continue;
|
|
4374
|
+
const pattern = line.split("").map((ch) => {
|
|
4375
|
+
if (ch === "*") return ".*";
|
|
4376
|
+
if (ch === "?") return ".";
|
|
4377
|
+
return ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
4378
|
+
}).join("");
|
|
4379
|
+
const re = new RegExp(line.includes("/") || anchored ? `^${pattern}$` : `(^|/)${pattern}$`);
|
|
4380
|
+
matchers.push((rel, isDir) => {
|
|
4381
|
+
if (dirOnly && !isDir) return false;
|
|
4382
|
+
return re.test(rel);
|
|
4383
|
+
});
|
|
4384
|
+
}
|
|
4385
|
+
return matchers;
|
|
4386
|
+
}
|
|
4387
|
+
function makeIgnoreFilter(root) {
|
|
4388
|
+
const matchers = loadGitignore(root);
|
|
4389
|
+
return (rel, isDir) => {
|
|
4390
|
+
const name = rel.slice(rel.lastIndexOf("/") + 1);
|
|
4391
|
+
if (name.startsWith(".")) return true;
|
|
4392
|
+
if (isDir && ALWAYS_SKIP_DIRS.has(name)) return true;
|
|
4393
|
+
return matchers.some((m) => m(rel, isDir));
|
|
4394
|
+
};
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
// src/tools/files.ts
|
|
4208
4398
|
var DEFAULT_MAX_LINES = 2e3;
|
|
4209
4399
|
var MULTI_READ_MAX_TOTAL_LINES = 1500;
|
|
4210
4400
|
var MAX_LINE_CHARS = 500;
|
|
4401
|
+
var READ_CHUNK_BYTES = 64 * 1024;
|
|
4402
|
+
var RESULT_META_RESERVE = 800;
|
|
4211
4403
|
function makeReadFile(workspace, guard) {
|
|
4212
|
-
const root =
|
|
4213
|
-
function
|
|
4404
|
+
const root = path8.resolve(workspace);
|
|
4405
|
+
function readWindow(target, startLine, maxLines, charBudget, onDigest) {
|
|
4406
|
+
const fd = fs6.openSync(target, "r");
|
|
4407
|
+
try {
|
|
4408
|
+
const decoder = new StringDecoder("utf-8");
|
|
4409
|
+
const hash = createHash("sha256");
|
|
4410
|
+
const buf = Buffer.allocUnsafe(READ_CHUNK_BYTES);
|
|
4411
|
+
const lines = [];
|
|
4412
|
+
let lineNo = 0;
|
|
4413
|
+
let pending = "";
|
|
4414
|
+
let chars = 0;
|
|
4415
|
+
let capped = false;
|
|
4416
|
+
let pos = 0;
|
|
4417
|
+
const takeLine = (text) => {
|
|
4418
|
+
lineNo += 1;
|
|
4419
|
+
if (capped || lineNo < startLine || lines.length >= maxLines) return;
|
|
4420
|
+
const clipped = text.length > MAX_LINE_CHARS ? text.slice(0, MAX_LINE_CHARS) + "\u2026 (line truncated)" : text;
|
|
4421
|
+
const rendered = `${lineNo}|${clipped}`;
|
|
4422
|
+
if (chars + rendered.length + 1 > charBudget) {
|
|
4423
|
+
capped = true;
|
|
4424
|
+
return;
|
|
4425
|
+
}
|
|
4426
|
+
chars += rendered.length + 1;
|
|
4427
|
+
lines.push(rendered);
|
|
4428
|
+
};
|
|
4429
|
+
for (; ; ) {
|
|
4430
|
+
const n = fs6.readSync(fd, buf, 0, READ_CHUNK_BYTES, pos);
|
|
4431
|
+
if (n <= 0) break;
|
|
4432
|
+
pos += n;
|
|
4433
|
+
const decoded = decoder.write(buf.subarray(0, n));
|
|
4434
|
+
hash.update(decoded, "utf8");
|
|
4435
|
+
const text = pending + decoded;
|
|
4436
|
+
let from = 0;
|
|
4437
|
+
for (; ; ) {
|
|
4438
|
+
const idx = text.indexOf("\n", from);
|
|
4439
|
+
if (idx < 0) break;
|
|
4440
|
+
takeLine(text.slice(from, idx).replace(/\r$/, ""));
|
|
4441
|
+
from = idx + 1;
|
|
4442
|
+
}
|
|
4443
|
+
pending = text.slice(from);
|
|
4444
|
+
}
|
|
4445
|
+
const rest = decoder.end();
|
|
4446
|
+
if (rest) hash.update(rest, "utf8");
|
|
4447
|
+
const tail = pending + rest;
|
|
4448
|
+
if (tail.length > 0) takeLine(tail.replace(/\r$/, ""));
|
|
4449
|
+
onDigest(hash.digest("hex").slice(0, 16));
|
|
4450
|
+
return { lines, totalLines: lineNo, capped };
|
|
4451
|
+
} finally {
|
|
4452
|
+
fs6.closeSync(fd);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
function readOne(filePath, startLine, maxLines, charBudget) {
|
|
4214
4456
|
const resolved = resolveWithinRoot(root, filePath);
|
|
4215
4457
|
if (!resolved) {
|
|
4216
4458
|
return { path: filePath, error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
4217
4459
|
}
|
|
4218
4460
|
const target = resolved.real;
|
|
4219
|
-
if (!
|
|
4461
|
+
if (!fs6.existsSync(target) || !fs6.statSync(target).isFile()) {
|
|
4220
4462
|
return { path: filePath, error: `\u4E0D\u662F\u6587\u4EF6: ${filePath}` };
|
|
4221
4463
|
}
|
|
4222
|
-
|
|
4223
|
-
let total = 0;
|
|
4464
|
+
let read;
|
|
4224
4465
|
try {
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
total = lines.length;
|
|
4229
|
-
for (let i = startLine - 1; i < Math.min(startLine - 1 + maxLines, lines.length); i++) {
|
|
4230
|
-
let text = lines[i];
|
|
4231
|
-
if (text.length > MAX_LINE_CHARS) {
|
|
4232
|
-
text = text.slice(0, MAX_LINE_CHARS) + "\u2026 (line truncated)";
|
|
4233
|
-
}
|
|
4234
|
-
selected.push(`${i + 1}|${text}`);
|
|
4235
|
-
}
|
|
4466
|
+
read = readWindow(target, startLine, maxLines, charBudget, (digest) => {
|
|
4467
|
+
guard?.noteReadDigest(target, digest);
|
|
4468
|
+
});
|
|
4236
4469
|
} catch (exc) {
|
|
4237
4470
|
return { path: filePath, error: `\u8BFB\u53D6\u5931\u8D25: ${String(exc)}` };
|
|
4238
4471
|
}
|
|
4472
|
+
const { lines: selected, totalLines: total, capped } = read;
|
|
4239
4473
|
const end = startLine + selected.length - 1;
|
|
4240
4474
|
const result = {
|
|
4241
|
-
path:
|
|
4475
|
+
path: path8.relative(resolved.root, target),
|
|
4242
4476
|
start_line: startLine,
|
|
4243
4477
|
end_line: end,
|
|
4244
4478
|
total_lines: total,
|
|
4245
4479
|
content: selected.join("\n")
|
|
4246
4480
|
};
|
|
4247
|
-
if (
|
|
4481
|
+
if (capped) {
|
|
4482
|
+
result.note = `\u5DF2\u8FD4\u56DE\u7B2C ${startLine}-${end} \u884C\uFF08\u672C\u6B21\u5DF2\u8FBE\u5355\u6B21\u8BFB\u53D6\u4E0A\u9650\u7EA6 ${charBudget} \u5B57\u7B26\uFF0C\u5171 ${total} \u884C\uFF09\uFF1B\u8C03\u7528 read_file(start_line=${end + 1}) \u7EE7\u7EED\u9605\u8BFB`;
|
|
4483
|
+
} else if (end < total) {
|
|
4248
4484
|
result.note = `\u663E\u793A\u7B2C ${startLine}-${end} \u884C\uFF0C\u5171 ${total} \u884C\uFF1B\u8C03\u7528 read_file(start_line=${end + 1}) \u7EE7\u7EED\u9605\u8BFB`;
|
|
4249
4485
|
}
|
|
4250
4486
|
return result;
|
|
4251
4487
|
}
|
|
4252
4488
|
return function read_file(args) {
|
|
4253
4489
|
const startLine = Math.max(1, Number(args.start_line ?? 1));
|
|
4254
|
-
const
|
|
4490
|
+
const requestedLines = Number(args.max_lines ?? DEFAULT_MAX_LINES);
|
|
4491
|
+
const maxLines = Number.isFinite(requestedLines) ? Math.min(Math.max(1, Math.floor(requestedLines)), DEFAULT_MAX_LINES) : DEFAULT_MAX_LINES;
|
|
4492
|
+
const fullBudget = Math.max(1e3, toolResultBudget("read_file") - RESULT_META_RESERVE);
|
|
4255
4493
|
const paths = Array.isArray(args.paths) ? args.paths.map((p) => String(p ?? "")).filter(Boolean) : [];
|
|
4256
4494
|
if (paths.length > 0) {
|
|
4495
|
+
const perFileBudget = Math.max(1e3, Math.floor(fullBudget / paths.length));
|
|
4257
4496
|
const files = [];
|
|
4258
4497
|
let remainingLines = MULTI_READ_MAX_TOTAL_LINES;
|
|
4259
4498
|
for (const filePath2 of paths) {
|
|
4260
4499
|
const perFile = Math.min(maxLines, Math.max(1, remainingLines));
|
|
4261
|
-
const one = readOne(filePath2, startLine, perFile);
|
|
4500
|
+
const one = readOne(filePath2, startLine, perFile, perFileBudget);
|
|
4262
4501
|
files.push(one);
|
|
4263
4502
|
if (!one.error) remainingLines -= one.content.split("\n").length;
|
|
4264
4503
|
if (remainingLines <= 0) break;
|
|
@@ -4273,31 +4512,79 @@ function makeReadFile(workspace, guard) {
|
|
|
4273
4512
|
if (!filePath) {
|
|
4274
4513
|
return { error: "\u7F3A\u5C11 path\uFF08\u6216 paths\uFF09\u53C2\u6570" };
|
|
4275
4514
|
}
|
|
4276
|
-
return readOne(filePath, startLine, maxLines);
|
|
4515
|
+
return readOne(filePath, startLine, maxLines, fullBudget);
|
|
4277
4516
|
};
|
|
4278
4517
|
}
|
|
4518
|
+
var DEFAULT_LIST_DEPTH = 3;
|
|
4519
|
+
var MAX_LIST_DEPTH = 6;
|
|
4520
|
+
var DEFAULT_RECURSIVE_LIMIT = 400;
|
|
4521
|
+
var MAX_RECURSIVE_LIMIT = 1e3;
|
|
4279
4522
|
function makeListFiles(workspace) {
|
|
4280
|
-
const root =
|
|
4523
|
+
const root = path8.resolve(workspace);
|
|
4281
4524
|
return function list_files(args) {
|
|
4282
4525
|
const dirPath = String(args.path ?? ".");
|
|
4283
|
-
const
|
|
4526
|
+
const recursive = args.recursive === true;
|
|
4527
|
+
const requestedMax = Number(args.max_results ?? (recursive ? DEFAULT_RECURSIVE_LIMIT : 100));
|
|
4528
|
+
const hardCap = recursive ? MAX_RECURSIVE_LIMIT : 100;
|
|
4529
|
+
const maxResults = Number.isFinite(requestedMax) ? Math.max(1, Math.min(Math.floor(requestedMax), hardCap)) : hardCap;
|
|
4530
|
+
const requestedDepth = Number(args.max_depth ?? DEFAULT_LIST_DEPTH);
|
|
4531
|
+
const maxDepth = Number.isFinite(requestedDepth) ? Math.max(1, Math.min(Math.floor(requestedDepth), MAX_LIST_DEPTH)) : DEFAULT_LIST_DEPTH;
|
|
4284
4532
|
const resolved = resolveWithinRoot(root, dirPath);
|
|
4285
4533
|
if (!resolved) return { error: "\u8DEF\u5F84\u5728\u5DE5\u4F5C\u533A\u4E4B\u5916" };
|
|
4286
4534
|
const target = resolved.real;
|
|
4287
|
-
if (!
|
|
4535
|
+
if (!fs6.existsSync(target) || !fs6.statSync(target).isDirectory()) {
|
|
4288
4536
|
return { error: `\u4E0D\u662F\u76EE\u5F55: ${dirPath}` };
|
|
4289
4537
|
}
|
|
4538
|
+
const realRoot = resolved.root;
|
|
4539
|
+
const isIgnored = makeIgnoreFilter(realRoot);
|
|
4290
4540
|
try {
|
|
4291
|
-
|
|
4541
|
+
if (!recursive) {
|
|
4542
|
+
const results2 = [];
|
|
4543
|
+
for (const e of fs6.readdirSync(target, { withFileTypes: true })) {
|
|
4544
|
+
if (results2.length >= maxResults) break;
|
|
4545
|
+
const rel = path8.relative(realRoot, path8.join(target, e.name)).split(path8.sep).join("/");
|
|
4546
|
+
if (isIgnored(rel, e.isDirectory())) continue;
|
|
4547
|
+
results2.push(e.isDirectory() ? `${e.name}/` : e.name);
|
|
4548
|
+
}
|
|
4549
|
+
results2.sort();
|
|
4550
|
+
return { path: path8.relative(realRoot, target), entries: results2.slice(0, maxResults) };
|
|
4551
|
+
}
|
|
4292
4552
|
const results = [];
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4553
|
+
let truncated = false;
|
|
4554
|
+
const queue = [{ dir: target, depth: 1 }];
|
|
4555
|
+
while (queue.length > 0) {
|
|
4556
|
+
const { dir, depth } = queue.shift();
|
|
4557
|
+
let entries;
|
|
4558
|
+
try {
|
|
4559
|
+
entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
4560
|
+
} catch {
|
|
4561
|
+
continue;
|
|
4562
|
+
}
|
|
4563
|
+
entries.sort((a, b) => {
|
|
4564
|
+
if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;
|
|
4565
|
+
return a.name.localeCompare(b.name, "zh");
|
|
4566
|
+
});
|
|
4567
|
+
for (const e of entries) {
|
|
4568
|
+
if (results.length >= maxResults) {
|
|
4569
|
+
truncated = true;
|
|
4570
|
+
break;
|
|
4571
|
+
}
|
|
4572
|
+
const full = path8.join(dir, e.name);
|
|
4573
|
+
const rel = path8.relative(realRoot, full).split(path8.sep).join("/");
|
|
4574
|
+
const isDir = e.isDirectory();
|
|
4575
|
+
if (isIgnored(rel, isDir)) continue;
|
|
4576
|
+
results.push(isDir ? `${rel}/` : rel);
|
|
4577
|
+
if (isDir && depth < maxDepth) queue.push({ dir: full, depth: depth + 1 });
|
|
4578
|
+
}
|
|
4579
|
+
if (truncated) break;
|
|
4298
4580
|
}
|
|
4299
|
-
|
|
4300
|
-
|
|
4581
|
+
return {
|
|
4582
|
+
path: path8.relative(realRoot, target),
|
|
4583
|
+
entries: results,
|
|
4584
|
+
...truncated ? {
|
|
4585
|
+
note: `\u5DF2\u8FBE\u5230\u6761\u76EE\u4E0A\u9650 ${maxResults}\uFF0C\u7ED3\u679C\u88AB\u622A\u65AD\uFF1B\u8BF7\u7F29\u5C0F path \u5230\u5177\u4F53\u5B50\u76EE\u5F55\uFF0C\u6216\u964D\u4F4E max_depth\uFF08\u5F53\u524D ${maxDepth}\uFF09`
|
|
4586
|
+
} : {}
|
|
4587
|
+
};
|
|
4301
4588
|
} catch (exc) {
|
|
4302
4589
|
return { error: `\u5217\u51FA\u6587\u4EF6\u5931\u8D25: ${String(exc)}` };
|
|
4303
4590
|
}
|
|
@@ -4337,12 +4624,23 @@ function registerReadOnlyFileTools(registry, workspace, guard) {
|
|
|
4337
4624
|
type: "function",
|
|
4338
4625
|
function: {
|
|
4339
4626
|
name: "list_files",
|
|
4340
|
-
description: "\u5217\u51FA\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u548C\u5B50\u76EE\u5F55\u3002\u8DF3\u8FC7\u9690\u85CF\
|
|
4627
|
+
description: "\u5217\u51FA\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u548C\u5B50\u76EE\u5F55\u3002\u8DF3\u8FC7\u9690\u85CF\u9879\u3001\u5E38\u89C1\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\uFF0C\u5E76\u9075\u5B88\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u7684 .gitignore\u3002\u4E86\u89E3\u5927\u4ED3\u5E93\u7ED3\u6784\u65F6\u7528 recursive=true \u4E00\u6B21\u62FF\u5230\u6709\u9650\u6DF1\u5EA6\uFF08\u9ED8\u8BA4 3 \u5C42\uFF09\u7684\u6811\uFF0C\u6BD4\u9010\u5C42\u8C03\u7528\u7701\u5F88\u591A\u5F80\u8FD4\uFF1B\u6761\u76EE\u8FC7\u591A\u65F6\u4F1A\u622A\u65AD\u5E76\u63D0\u793A\u3002",
|
|
4341
4628
|
parameters: {
|
|
4342
4629
|
type: "object",
|
|
4343
4630
|
properties: {
|
|
4344
4631
|
path: { type: "string", description: "\u76EE\u5F55\u8DEF\u5F84 (\u76F8\u5BF9\u4E8E\u5DE5\u4F5C\u533A\uFF0C\u9ED8\u8BA4 '.')" },
|
|
4345
|
-
|
|
4632
|
+
recursive: {
|
|
4633
|
+
type: "boolean",
|
|
4634
|
+
description: "\u9012\u5F52\u5217\u51FA\u5B50\u76EE\u5F55\uFF08\u9ED8\u8BA4 false\uFF0C\u53EA\u5217\u4E00\u5C42\uFF09"
|
|
4635
|
+
},
|
|
4636
|
+
max_depth: {
|
|
4637
|
+
type: "integer",
|
|
4638
|
+
description: `\u9012\u5F52\u6DF1\u5EA6 (\u9ED8\u8BA4 ${DEFAULT_LIST_DEPTH}\uFF0C\u4E0A\u9650 ${MAX_LIST_DEPTH}\uFF1B\u4EC5 recursive \u65F6\u751F\u6548)`
|
|
4639
|
+
},
|
|
4640
|
+
max_results: {
|
|
4641
|
+
type: "integer",
|
|
4642
|
+
description: `\u6700\u5927\u7ED3\u679C\u6570\uFF08\u975E\u9012\u5F52\u9ED8\u8BA4 100 / \u4E0A\u9650 100\uFF1B\u9012\u5F52\u9ED8\u8BA4 ${DEFAULT_RECURSIVE_LIMIT} / \u4E0A\u9650 ${MAX_RECURSIVE_LIMIT}\uFF09`
|
|
4643
|
+
}
|
|
4346
4644
|
}
|
|
4347
4645
|
}
|
|
4348
4646
|
}
|
|
@@ -4510,10 +4808,10 @@ function execAsync(file, argv, opts = {}) {
|
|
|
4510
4808
|
}
|
|
4511
4809
|
|
|
4512
4810
|
// src/tools/shellRuntime.ts
|
|
4513
|
-
import * as
|
|
4811
|
+
import * as path9 from "path";
|
|
4514
4812
|
var WINDOWS_SUFFIXES = [".exe", ".cmd", ".bat", ".com", ""];
|
|
4515
4813
|
function pathApi(platform) {
|
|
4516
|
-
return platform === "win32" ?
|
|
4814
|
+
return platform === "win32" ? path9.win32 : path9.posix;
|
|
4517
4815
|
}
|
|
4518
4816
|
function joinPath(platform, ...parts) {
|
|
4519
4817
|
return pathApi(platform).join(...parts);
|
|
@@ -4726,8 +5024,8 @@ function decodeOutput(buf) {
|
|
|
4726
5024
|
var shellTasks = new ShellTaskManager();
|
|
4727
5025
|
|
|
4728
5026
|
// src/tools/nodeGrep.ts
|
|
4729
|
-
import * as
|
|
4730
|
-
import * as
|
|
5027
|
+
import * as fs7 from "fs";
|
|
5028
|
+
import * as path10 from "path";
|
|
4731
5029
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
4732
5030
|
".git",
|
|
4733
5031
|
"node_modules",
|
|
@@ -4752,27 +5050,27 @@ function nodeGrep(opts) {
|
|
|
4752
5050
|
} catch (err) {
|
|
4753
5051
|
throw new Error(`\u65E0\u6548\u7684\u6B63\u5219\u8868\u8FBE\u5F0F: ${opts.pattern}\uFF08${String(err)}\uFF09`);
|
|
4754
5052
|
}
|
|
4755
|
-
const target =
|
|
4756
|
-
if (!
|
|
5053
|
+
const target = path10.resolve(opts.workspace, opts.target);
|
|
5054
|
+
if (!fs7.existsSync(target)) {
|
|
4757
5055
|
throw new Error(`\u641C\u7D22\u8DEF\u5F84\u4E0D\u5B58\u5728: ${opts.target}`);
|
|
4758
5056
|
}
|
|
4759
5057
|
const matches = [];
|
|
4760
5058
|
const scanFile = (file) => {
|
|
4761
5059
|
let stat2;
|
|
4762
5060
|
try {
|
|
4763
|
-
stat2 =
|
|
5061
|
+
stat2 = fs7.statSync(file);
|
|
4764
5062
|
} catch {
|
|
4765
5063
|
return false;
|
|
4766
5064
|
}
|
|
4767
5065
|
if (!stat2.isFile() || stat2.size > maxFileBytes) return false;
|
|
4768
5066
|
let buf;
|
|
4769
5067
|
try {
|
|
4770
|
-
buf =
|
|
5068
|
+
buf = fs7.readFileSync(file);
|
|
4771
5069
|
} catch {
|
|
4772
5070
|
return false;
|
|
4773
5071
|
}
|
|
4774
5072
|
if (looksBinary(buf)) return false;
|
|
4775
|
-
const rel =
|
|
5073
|
+
const rel = path10.relative(opts.workspace, file) || path10.basename(file);
|
|
4776
5074
|
const lines = buf.toString("utf-8").split("\n");
|
|
4777
5075
|
for (let i = 0; i < lines.length; i++) {
|
|
4778
5076
|
const raw = lines[i].replace(/\r$/, "");
|
|
@@ -4783,7 +5081,7 @@ function nodeGrep(opts) {
|
|
|
4783
5081
|
}
|
|
4784
5082
|
return false;
|
|
4785
5083
|
};
|
|
4786
|
-
const stat =
|
|
5084
|
+
const stat = fs7.statSync(target);
|
|
4787
5085
|
if (stat.isFile()) {
|
|
4788
5086
|
scanFile(target);
|
|
4789
5087
|
return matches;
|
|
@@ -4793,12 +5091,12 @@ function nodeGrep(opts) {
|
|
|
4793
5091
|
const dir = stack.pop();
|
|
4794
5092
|
let entries;
|
|
4795
5093
|
try {
|
|
4796
|
-
entries =
|
|
5094
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
4797
5095
|
} catch {
|
|
4798
5096
|
continue;
|
|
4799
5097
|
}
|
|
4800
5098
|
for (const entry of entries) {
|
|
4801
|
-
const full =
|
|
5099
|
+
const full = path10.join(dir, entry.name);
|
|
4802
5100
|
if (entry.isDirectory()) {
|
|
4803
5101
|
if (!SKIP_DIRS.has(entry.name)) stack.push(full);
|
|
4804
5102
|
} else if (entry.isFile()) {
|
|
@@ -4810,22 +5108,22 @@ function nodeGrep(opts) {
|
|
|
4810
5108
|
}
|
|
4811
5109
|
|
|
4812
5110
|
// src/tools/ripgrep.ts
|
|
4813
|
-
import * as
|
|
5111
|
+
import * as fs8 from "fs";
|
|
4814
5112
|
import * as os3 from "os";
|
|
4815
|
-
import * as
|
|
5113
|
+
import * as path11 from "path";
|
|
4816
5114
|
import { createRequire } from "module";
|
|
4817
5115
|
var cached;
|
|
4818
5116
|
function extractBundledRipgrep() {
|
|
4819
5117
|
try {
|
|
4820
|
-
const req = typeof __require === "function" ? __require : createRequire(
|
|
5118
|
+
const req = typeof __require === "function" ? __require : createRequire(path11.join(process.cwd(), "__zqagent__.js"));
|
|
4821
5119
|
const sea = req("node:sea");
|
|
4822
5120
|
if (!sea?.isSea?.() || typeof sea.getAsset !== "function") return null;
|
|
4823
5121
|
const asset = sea.getAsset("rg");
|
|
4824
5122
|
if (!asset) return null;
|
|
4825
|
-
const dir =
|
|
4826
|
-
const file =
|
|
4827
|
-
|
|
4828
|
-
|
|
5123
|
+
const dir = fs8.mkdtempSync(path11.join(os3.tmpdir(), "zqagent-rg-"));
|
|
5124
|
+
const file = path11.join(dir, process.platform === "win32" ? "rg.exe" : "rg");
|
|
5125
|
+
fs8.writeFileSync(file, Buffer.from(asset));
|
|
5126
|
+
fs8.chmodSync(file, 493);
|
|
4829
5127
|
return file;
|
|
4830
5128
|
} catch {
|
|
4831
5129
|
return null;
|
|
@@ -4834,7 +5132,7 @@ function extractBundledRipgrep() {
|
|
|
4834
5132
|
function resolveRipgrep() {
|
|
4835
5133
|
if (cached !== void 0) return cached;
|
|
4836
5134
|
const explicit = (process.env.ZQAGENT_RG ?? "").trim();
|
|
4837
|
-
if (explicit &&
|
|
5135
|
+
if (explicit && fs8.existsSync(explicit)) {
|
|
4838
5136
|
cached = explicit;
|
|
4839
5137
|
return cached;
|
|
4840
5138
|
}
|
|
@@ -4848,7 +5146,7 @@ function resolveRipgrep() {
|
|
|
4848
5146
|
env: process.env,
|
|
4849
5147
|
fileExists: (p) => {
|
|
4850
5148
|
try {
|
|
4851
|
-
return
|
|
5149
|
+
return fs8.statSync(p).isFile();
|
|
4852
5150
|
} catch {
|
|
4853
5151
|
return false;
|
|
4854
5152
|
}
|
|
@@ -4858,12 +5156,61 @@ function resolveRipgrep() {
|
|
|
4858
5156
|
}
|
|
4859
5157
|
|
|
4860
5158
|
// src/tools/search.ts
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
5159
|
+
var DEFAULT_MAX_RESULTS = 50;
|
|
5160
|
+
var MAX_RESULTS_CAP = 200;
|
|
5161
|
+
var MAX_TEXT_CHARS = 200;
|
|
5162
|
+
var RG_TIMEOUT_MS = 1e4;
|
|
5163
|
+
function parseRgOutput(result, limit) {
|
|
5164
|
+
const out = [];
|
|
5165
|
+
for (const raw of result.split("\n")) {
|
|
5166
|
+
if (out.length >= limit) break;
|
|
5167
|
+
const line = raw.replace(/\r$/, "");
|
|
5168
|
+
if (!line) continue;
|
|
5169
|
+
const m = /^(.+?)[:-](\d+)[:-](.*)$/.exec(line);
|
|
5170
|
+
if (!m) continue;
|
|
5171
|
+
out.push({
|
|
5172
|
+
file: m[1],
|
|
5173
|
+
line: Number(m[2]),
|
|
5174
|
+
text: m[3].trim().slice(0, MAX_TEXT_CHARS)
|
|
5175
|
+
});
|
|
5176
|
+
}
|
|
5177
|
+
return out;
|
|
5178
|
+
}
|
|
5179
|
+
function parseRgFiles(result, limit) {
|
|
5180
|
+
const files = [];
|
|
5181
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5182
|
+
for (const raw of result.split("\n")) {
|
|
5183
|
+
if (files.length >= limit) break;
|
|
5184
|
+
const f = raw.replace(/\r$/, "").trim();
|
|
5185
|
+
if (!f || seen.has(f)) continue;
|
|
5186
|
+
seen.add(f);
|
|
5187
|
+
files.push(f);
|
|
5188
|
+
}
|
|
5189
|
+
return files;
|
|
5190
|
+
}
|
|
5191
|
+
function rgArgs(opts) {
|
|
5192
|
+
const args = [];
|
|
5193
|
+
if (opts.filesOnly) {
|
|
5194
|
+
args.push("--files-with-matches");
|
|
5195
|
+
} else {
|
|
5196
|
+
args.push("--with-filename", "--line-number", "--no-heading");
|
|
5197
|
+
args.push("--max-count", String(Math.max(opts.maxResults, 1)));
|
|
5198
|
+
}
|
|
5199
|
+
if (opts.ignoreCase) args.push("--ignore-case");
|
|
5200
|
+
if (opts.glob) args.push("--glob", opts.glob);
|
|
5201
|
+
if (opts.contextLines > 0 && !opts.filesOnly) {
|
|
5202
|
+
args.push("--context", String(opts.contextLines));
|
|
5203
|
+
}
|
|
5204
|
+
args.push("--", opts.pattern, opts.path);
|
|
5205
|
+
return args;
|
|
5206
|
+
}
|
|
5207
|
+
function rgFailureHint(res) {
|
|
5208
|
+
if (res.timedOut) {
|
|
5209
|
+
return `\u641C\u7D22\u8D85\u65F6\uFF08${RG_TIMEOUT_MS / 1e3}s\uFF09\u3002\u5927\u4ED3\u5E93\u5168\u91CF\u641C\u7D22\u5F88\u5BB9\u6613\u8D85\u65F6\uFF1A\u8BF7\u7F29\u5C0F path \u5230\u5177\u4F53\u5B50\u76EE\u5F55\uFF0C\u6216\u7528 glob \u53C2\u6570\u9650\u5236\u6587\u4EF6\u7C7B\u578B\uFF08\u5982 "*.ts"\uFF09\u540E\u91CD\u8BD5`;
|
|
5210
|
+
}
|
|
5211
|
+
if (res.aborted) return "\u641C\u7D22\u5DF2\u4E2D\u65AD";
|
|
5212
|
+
const stderr = decodeOutput(res.stderr).trim().slice(0, 300);
|
|
5213
|
+
return `\u641C\u7D22\u5931\u8D25\uFF08rg \u9000\u51FA\u7801 ${String(res.status)}\uFF09${stderr ? `\uFF1A${stderr}` : ""}`;
|
|
4867
5214
|
}
|
|
4868
5215
|
function makeGrep(workspace) {
|
|
4869
5216
|
return async function grep(args) {
|
|
@@ -4872,37 +5219,50 @@ function makeGrep(workspace) {
|
|
|
4872
5219
|
if (!pattern.trim()) {
|
|
4873
5220
|
return { error: "\u641C\u7D22\u6A21\u5F0F\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
4874
5221
|
}
|
|
5222
|
+
const filesOnly = args.files_only === true;
|
|
5223
|
+
const ignoreCase = args.ignore_case === true;
|
|
5224
|
+
const glob = typeof args.glob === "string" && args.glob.trim() ? args.glob.trim() : void 0;
|
|
5225
|
+
const contextLines = Math.max(
|
|
5226
|
+
0,
|
|
5227
|
+
Math.min(Number(args.context_lines ?? 0) || 0, 5)
|
|
5228
|
+
);
|
|
5229
|
+
const maxResults = Math.max(
|
|
5230
|
+
1,
|
|
5231
|
+
Math.min(Number(args.max_results ?? DEFAULT_MAX_RESULTS) || DEFAULT_MAX_RESULTS, MAX_RESULTS_CAP)
|
|
5232
|
+
);
|
|
4875
5233
|
const rg = resolveRipgrep();
|
|
4876
5234
|
if (rg) {
|
|
4877
5235
|
const res = await execAsync(
|
|
4878
5236
|
rg,
|
|
4879
|
-
|
|
4880
|
-
// --with-filename:单文件模式下 rg 默认不输出文件名前缀,会导致
|
|
4881
|
-
// "行号:内容" 被误当成 "文件:行号:内容" 解析而错位;显式要求带文件名。
|
|
4882
|
-
"--with-filename",
|
|
4883
|
-
"--line-number",
|
|
4884
|
-
"--no-heading",
|
|
4885
|
-
"--max-count",
|
|
4886
|
-
"50",
|
|
4887
|
-
pattern,
|
|
4888
|
-
filePath
|
|
4889
|
-
],
|
|
5237
|
+
rgArgs({ pattern, path: filePath, filesOnly, ignoreCase, glob, contextLines, maxResults }),
|
|
4890
5238
|
{
|
|
4891
5239
|
cwd: workspace,
|
|
4892
|
-
timeoutMs:
|
|
5240
|
+
timeoutMs: RG_TIMEOUT_MS,
|
|
4893
5241
|
maxBuffer: 1024 * 1024 * 2
|
|
4894
5242
|
}
|
|
4895
5243
|
);
|
|
4896
5244
|
if (res.status === 0) {
|
|
4897
|
-
const
|
|
4898
|
-
return { query: pattern, engine: "ripgrep",
|
|
5245
|
+
const out = decodeOutput(res.stdout);
|
|
5246
|
+
return filesOnly ? { query: pattern, engine: "ripgrep", files: parseRgFiles(out, maxResults) } : (() => {
|
|
5247
|
+
const matches = parseRgOutput(out, maxResults);
|
|
5248
|
+
return { query: pattern, engine: "ripgrep", matches, count: matches.length };
|
|
5249
|
+
})();
|
|
4899
5250
|
}
|
|
4900
5251
|
if (res.status === 1) {
|
|
4901
|
-
return { query: pattern, engine: "ripgrep", matches: [], count: 0 };
|
|
5252
|
+
return filesOnly ? { query: pattern, engine: "ripgrep", files: [], count: 0 } : { query: pattern, engine: "ripgrep", matches: [], count: 0 };
|
|
5253
|
+
}
|
|
5254
|
+
if (!res.error) {
|
|
5255
|
+
return { query: pattern, error: rgFailureHint(res) };
|
|
4902
5256
|
}
|
|
4903
5257
|
}
|
|
5258
|
+
if (filesOnly || glob || ignoreCase || contextLines > 0) {
|
|
5259
|
+
return {
|
|
5260
|
+
query: pattern,
|
|
5261
|
+
error: "\u5F53\u524D\u8282\u70B9\u672A\u5B89\u88C5 ripgrep\uFF0Cfiles_only / glob / ignore_case / context_lines \u9700\u8981 ripgrep \u624D\u80FD\u751F\u6548\uFF1B\u8BF7\u53BB\u6389\u8FD9\u4E9B\u53C2\u6570\u540E\u91CD\u8BD5\uFF0C\u6216\u5148\u5B89\u88C5 ripgrep"
|
|
5262
|
+
};
|
|
5263
|
+
}
|
|
4904
5264
|
try {
|
|
4905
|
-
const matches = nodeGrep({ pattern, target: filePath, workspace });
|
|
5265
|
+
const matches = nodeGrep({ pattern, target: filePath, workspace, maxMatches: maxResults });
|
|
4906
5266
|
return { query: pattern, engine: "node", matches, count: matches.length };
|
|
4907
5267
|
} catch (exc) {
|
|
4908
5268
|
return { error: `\u641C\u7D22\u5931\u8D25: ${String(exc instanceof Error ? exc.message : exc)}` };
|
|
@@ -4918,12 +5278,29 @@ function registerSearchTool(registry, workspace) {
|
|
|
4918
5278
|
type: "function",
|
|
4919
5279
|
function: {
|
|
4920
5280
|
name: "grep",
|
|
4921
|
-
description: "\u5728\u6587\u4EF6\u4E2D\u641C\u7D22\u6587\u672C\u6A21\u5F0F\uFF08\u652F\u6301\u5B8C\u6574 JS \u6B63\u5219\u8BED\u6CD5\uFF09\u3002\u8FD4\u56DE\u5339\u914D\u7684\u6587\u4EF6\u540D\u3001\u884C\u53F7\u548C\u5185\u5BB9\
|
|
5281
|
+
description: "\u5728\u6587\u4EF6\u4E2D\u641C\u7D22\u6587\u672C\u6A21\u5F0F\uFF08\u652F\u6301\u5B8C\u6574 JS \u6B63\u5219\u8BED\u6CD5\uFF09\u3002\u9ED8\u8BA4\u8FD4\u56DE\u5339\u914D\u7684\u6587\u4EF6\u540D\u3001\u884C\u53F7\u548C\u5185\u5BB9\uFF08\u6700\u591A 50 \u6761\uFF09\u3002\u5B9A\u4F4D\u4EE3\u7801\u4F4D\u7F6E\u65F6\u4F18\u5148\u7528 files_only=true \u53EA\u53D6\u6587\u4EF6\u5217\u8868\uFF08\u4F53\u79EF\u5C0F\u4E00\u4E2A\u6570\u91CF\u7EA7\uFF09\uFF0C\u518D\u7528 read_file \u7CBE\u51C6\u8BFB\u53D6\uFF1B\u5927\u4ED3\u5E93\u8BF7\u914D\u5408 path \u7F29\u5C0F\u8303\u56F4\u6216 glob \u9650\u5236\u6587\u4EF6\u7C7B\u578B\uFF0C\u907F\u514D\u5168\u91CF\u626B\u63CF\u8D85\u65F6\u3002",
|
|
4922
5282
|
parameters: {
|
|
4923
5283
|
type: "object",
|
|
4924
5284
|
properties: {
|
|
4925
5285
|
pattern: { type: "string", description: "\u641C\u7D22\u6A21\u5F0F (\u6587\u672C\u6216\u6B63\u5219\u8868\u8FBE\u5F0F)" },
|
|
4926
|
-
path: { type: "string", description: "\u641C\u7D22\u8DEF\u5F84 (\u6587\u4EF6\u6216\u76EE\u5F55\uFF0C\u9ED8\u8BA4 '.')" }
|
|
5286
|
+
path: { type: "string", description: "\u641C\u7D22\u8DEF\u5F84 (\u6587\u4EF6\u6216\u76EE\u5F55\uFF0C\u9ED8\u8BA4 '.'\uFF1B\u5927\u4ED3\u5E93\u5EFA\u8BAE\u5148\u7F29\u5C0F\u5230\u5B50\u76EE\u5F55)" },
|
|
5287
|
+
files_only: {
|
|
5288
|
+
type: "boolean",
|
|
5289
|
+
description: "\u53EA\u8FD4\u56DE\u5339\u914D\u7684\u6587\u4EF6\u8DEF\u5F84\uFF0C\u4E0D\u8FD4\u56DE\u884C\u5185\u5BB9\uFF08\u63A8\u8350\u7528\u4E8E\u5B9A\u4F4D\uFF0C\u663E\u8457\u8282\u7701\u4E0A\u4E0B\u6587\uFF09"
|
|
5290
|
+
},
|
|
5291
|
+
glob: {
|
|
5292
|
+
type: "string",
|
|
5293
|
+
description: '\u6587\u4EF6\u8FC7\u6EE4\uFF0C\u5982 "*.ts" \u6216 "!*.min.js"\uFF08\u53EF\u591A\u6B21\u6392\u9664\u9700\u81EA\u884C\u7EC4\u5408\u4E3A {a,b} \u5F62\u5F0F\uFF09'
|
|
5294
|
+
},
|
|
5295
|
+
ignore_case: { type: "boolean", description: "\u5FFD\u7565\u5927\u5C0F\u5199" },
|
|
5296
|
+
context_lines: {
|
|
5297
|
+
type: "integer",
|
|
5298
|
+
description: "\u6BCF\u6761\u547D\u4E2D\u9644\u5E26\u7684\u524D\u540E\u4E0A\u4E0B\u6587\u884C\u6570\uFF080-5\uFF0C\u9ED8\u8BA4 0\uFF09"
|
|
5299
|
+
},
|
|
5300
|
+
max_results: {
|
|
5301
|
+
type: "integer",
|
|
5302
|
+
description: `\u6700\u591A\u8FD4\u56DE\u6761\u6570\uFF08\u9ED8\u8BA4 ${DEFAULT_MAX_RESULTS}\uFF0C\u4E0A\u9650 ${MAX_RESULTS_CAP}\uFF09`
|
|
5303
|
+
}
|
|
4927
5304
|
},
|
|
4928
5305
|
required: ["pattern"]
|
|
4929
5306
|
}
|
|
@@ -4933,8 +5310,8 @@ function registerSearchTool(registry, workspace) {
|
|
|
4933
5310
|
}
|
|
4934
5311
|
|
|
4935
5312
|
// src/tools/git.ts
|
|
4936
|
-
import * as
|
|
4937
|
-
import * as
|
|
5313
|
+
import * as fs9 from "fs";
|
|
5314
|
+
import * as path12 from "path";
|
|
4938
5315
|
async function runGit(repoDir, args, timeout = 15e3) {
|
|
4939
5316
|
const res = await execAsync("git", ["-c", "core.quotepath=false", ...args], {
|
|
4940
5317
|
cwd: repoDir,
|
|
@@ -4951,9 +5328,9 @@ async function runGit(repoDir, args, timeout = 15e3) {
|
|
|
4951
5328
|
async function resolveRepoRoot(workspace, pathArg) {
|
|
4952
5329
|
let dir = workspace;
|
|
4953
5330
|
if (pathArg) {
|
|
4954
|
-
const abs =
|
|
5331
|
+
const abs = path12.resolve(workspace, pathArg);
|
|
4955
5332
|
try {
|
|
4956
|
-
dir =
|
|
5333
|
+
dir = fs9.statSync(abs).isDirectory() ? abs : path12.dirname(abs);
|
|
4957
5334
|
} catch {
|
|
4958
5335
|
dir = abs;
|
|
4959
5336
|
}
|
|
@@ -4966,22 +5343,22 @@ function repoDirArg(workspace, raw) {
|
|
|
4966
5343
|
if (typeof raw !== "string") return void 0;
|
|
4967
5344
|
const v = raw.trim();
|
|
4968
5345
|
if (!v) return void 0;
|
|
4969
|
-
const base =
|
|
4970
|
-
const abs =
|
|
4971
|
-
const rel =
|
|
5346
|
+
const base = path12.resolve(workspace);
|
|
5347
|
+
const abs = path12.resolve(base, v);
|
|
5348
|
+
const rel = path12.relative(base, abs);
|
|
4972
5349
|
if (!isInsideRelative(rel)) return void 0;
|
|
4973
5350
|
return abs;
|
|
4974
5351
|
}
|
|
4975
5352
|
function toPathspec(repoRoot, workspace, pathArg) {
|
|
4976
5353
|
if (!pathArg) return null;
|
|
4977
|
-
const abs =
|
|
4978
|
-
let rel =
|
|
5354
|
+
const abs = path12.resolve(workspace, pathArg);
|
|
5355
|
+
let rel = path12.relative(repoRoot, abs);
|
|
4979
5356
|
if (rel === "") return ".";
|
|
4980
5357
|
if (!isInsideRelative(rel)) {
|
|
4981
5358
|
try {
|
|
4982
|
-
const realRepo =
|
|
4983
|
-
const realAbs =
|
|
4984
|
-
const rel2 =
|
|
5359
|
+
const realRepo = fs9.realpathSync(repoRoot);
|
|
5360
|
+
const realAbs = fs9.realpathSync(abs);
|
|
5361
|
+
const rel2 = path12.relative(realRepo, realAbs);
|
|
4985
5362
|
if (rel2 === "") return ".";
|
|
4986
5363
|
if (isInsideRelative(rel2)) return rel2;
|
|
4987
5364
|
} catch {
|