@morphllm/morphsdk 0.2.21 → 0.2.22
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/{chunk-DF2ZOO7R.js → chunk-5VQEQSJQ.js} +3 -52
- package/dist/chunk-5VQEQSJQ.js.map +1 -0
- package/dist/chunk-73RQWOQC.js +16 -0
- package/dist/chunk-73RQWOQC.js.map +1 -0
- package/dist/{chunk-2DXRTGRH.js → chunk-74ZHKB54.js} +1 -1
- package/dist/{chunk-2DXRTGRH.js.map → chunk-74ZHKB54.js.map} +1 -1
- package/dist/chunk-AFEPUNAO.js +15 -0
- package/dist/chunk-AFEPUNAO.js.map +1 -0
- package/dist/chunk-EAA7D24N.js +201 -0
- package/dist/chunk-EAA7D24N.js.map +1 -0
- package/dist/chunk-EK7OQPWD.js +44 -0
- package/dist/chunk-EK7OQPWD.js.map +1 -0
- package/dist/chunk-FSVBNZMU.js +44 -0
- package/dist/chunk-FSVBNZMU.js.map +1 -0
- package/dist/chunk-G2RSY56Q.js +11 -0
- package/dist/chunk-G2RSY56Q.js.map +1 -0
- package/dist/chunk-GTOXMAF2.js +140 -0
- package/dist/chunk-GTOXMAF2.js.map +1 -0
- package/dist/chunk-HKZB23U7.js +85 -0
- package/dist/chunk-HKZB23U7.js.map +1 -0
- package/dist/chunk-JZGU5UC6.js +53 -0
- package/dist/chunk-JZGU5UC6.js.map +1 -0
- package/dist/chunk-NDZO5IPV.js +121 -0
- package/dist/chunk-NDZO5IPV.js.map +1 -0
- package/dist/{chunk-34F3D6JD.js → chunk-NSQGPBMU.js} +9 -9
- package/dist/chunk-RSLIOCOE.js +26 -0
- package/dist/chunk-RSLIOCOE.js.map +1 -0
- package/dist/chunk-SMGZ6A64.js +53 -0
- package/dist/chunk-SMGZ6A64.js.map +1 -0
- package/dist/chunk-TICMYDII.js +81 -0
- package/dist/chunk-TICMYDII.js.map +1 -0
- package/dist/chunk-UYBIKZPM.js +135 -0
- package/dist/chunk-UYBIKZPM.js.map +1 -0
- package/dist/chunk-VBBJGWHY.js +73 -0
- package/dist/chunk-VBBJGWHY.js.map +1 -0
- package/dist/chunk-XQLKK2ZH.js +56 -0
- package/dist/chunk-XQLKK2ZH.js.map +1 -0
- package/dist/chunk-XYPMN4A3.js +1 -0
- package/dist/chunk-XYPMN4A3.js.map +1 -0
- package/dist/chunk-Z2FBMSNE.js +10 -0
- package/dist/chunk-Z2FBMSNE.js.map +1 -0
- package/dist/client.cjs +2 -51
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +4 -4
- package/dist/git/client.cjs +2 -51
- package/dist/git/client.cjs.map +1 -1
- package/dist/git/client.js +1 -1
- package/dist/git/index.cjs +2 -51
- package/dist/git/index.cjs.map +1 -1
- package/dist/git/index.js +2 -2
- package/dist/git/types.cjs.map +1 -1
- package/dist/index.cjs +2 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -10
- package/dist/tools/warp_grep/agent/config.cjs +41 -0
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/config.js +12 -0
- package/dist/tools/warp_grep/agent/config.js.map +1 -0
- package/dist/tools/warp_grep/agent/formatter.cjs +106 -0
- package/dist/tools/warp_grep/agent/formatter.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/formatter.js +10 -0
- package/dist/tools/warp_grep/agent/formatter.js.map +1 -0
- package/dist/tools/warp_grep/agent/grep_helpers.cjs +148 -0
- package/dist/tools/warp_grep/agent/grep_helpers.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/grep_helpers.js +14 -0
- package/dist/tools/warp_grep/agent/grep_helpers.js.map +1 -0
- package/dist/tools/warp_grep/agent/parser.cjs +165 -0
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/parser.js +10 -0
- package/dist/tools/warp_grep/agent/parser.js.map +1 -0
- package/dist/tools/warp_grep/agent/prompt.cjs +110 -0
- package/dist/tools/warp_grep/agent/prompt.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/prompt.js +10 -0
- package/dist/tools/warp_grep/agent/prompt.js.map +1 -0
- package/dist/tools/warp_grep/agent/runner.cjs +744 -0
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/runner.js +17 -0
- package/dist/tools/warp_grep/agent/runner.js.map +1 -0
- package/dist/tools/warp_grep/agent/types.cjs +19 -0
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -0
- package/dist/tools/warp_grep/agent/types.js +2 -0
- package/dist/tools/warp_grep/agent/types.js.map +1 -0
- package/dist/tools/warp_grep/anthropic.cjs +977 -0
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -0
- package/dist/tools/warp_grep/anthropic.js +22 -0
- package/dist/tools/warp_grep/anthropic.js.map +1 -0
- package/dist/tools/warp_grep/index.cjs +1136 -0
- package/dist/tools/warp_grep/index.cjs.map +1 -0
- package/dist/tools/warp_grep/index.js +48 -0
- package/dist/tools/warp_grep/index.js.map +1 -0
- package/dist/tools/warp_grep/openai.cjs +980 -0
- package/dist/tools/warp_grep/openai.cjs.map +1 -0
- package/dist/tools/warp_grep/openai.js +22 -0
- package/dist/tools/warp_grep/openai.js.map +1 -0
- package/dist/tools/warp_grep/providers/command.cjs +98 -0
- package/dist/tools/warp_grep/providers/command.cjs.map +1 -0
- package/dist/tools/warp_grep/providers/command.js +9 -0
- package/dist/tools/warp_grep/providers/command.js.map +1 -0
- package/dist/tools/warp_grep/providers/local.cjs +232 -0
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -0
- package/dist/tools/warp_grep/providers/local.js +12 -0
- package/dist/tools/warp_grep/providers/local.js.map +1 -0
- package/dist/tools/warp_grep/providers/types.cjs +19 -0
- package/dist/tools/warp_grep/providers/types.cjs.map +1 -0
- package/dist/tools/warp_grep/providers/types.js +1 -0
- package/dist/tools/warp_grep/providers/types.js.map +1 -0
- package/dist/tools/warp_grep/tools/analyse.cjs +40 -0
- package/dist/tools/warp_grep/tools/analyse.cjs.map +1 -0
- package/dist/tools/warp_grep/tools/analyse.js +8 -0
- package/dist/tools/warp_grep/tools/analyse.js.map +1 -0
- package/dist/tools/warp_grep/tools/finish.cjs +69 -0
- package/dist/tools/warp_grep/tools/finish.cjs.map +1 -0
- package/dist/tools/warp_grep/tools/finish.js +10 -0
- package/dist/tools/warp_grep/tools/finish.js.map +1 -0
- package/dist/tools/warp_grep/tools/grep.cjs +35 -0
- package/dist/tools/warp_grep/tools/grep.cjs.map +1 -0
- package/dist/tools/warp_grep/tools/grep.js +12 -0
- package/dist/tools/warp_grep/tools/grep.js.map +1 -0
- package/dist/tools/warp_grep/tools/read.cjs +34 -0
- package/dist/tools/warp_grep/tools/read.cjs.map +1 -0
- package/dist/tools/warp_grep/tools/read.js +8 -0
- package/dist/tools/warp_grep/tools/read.js.map +1 -0
- package/dist/tools/warp_grep/utils/files.cjs +45 -0
- package/dist/tools/warp_grep/utils/files.cjs.map +1 -0
- package/dist/tools/warp_grep/utils/files.js +8 -0
- package/dist/tools/warp_grep/utils/files.js.map +1 -0
- package/dist/tools/warp_grep/utils/format.cjs +42 -0
- package/dist/tools/warp_grep/utils/format.cjs.map +1 -0
- package/dist/tools/warp_grep/utils/format.js +18 -0
- package/dist/tools/warp_grep/utils/format.js.map +1 -0
- package/dist/tools/warp_grep/utils/paths.cjs +91 -0
- package/dist/tools/warp_grep/utils/paths.cjs.map +1 -0
- package/dist/tools/warp_grep/utils/paths.js +16 -0
- package/dist/tools/warp_grep/utils/paths.js.map +1 -0
- package/dist/tools/warp_grep/utils/ripgrep.cjs +50 -0
- package/dist/tools/warp_grep/utils/ripgrep.cjs.map +1 -0
- package/dist/tools/warp_grep/utils/ripgrep.js +8 -0
- package/dist/tools/warp_grep/utils/ripgrep.js.map +1 -0
- package/dist/tools/warp_grep/vercel.cjs +968 -0
- package/dist/tools/warp_grep/vercel.cjs.map +1 -0
- package/dist/tools/warp_grep/vercel.js +22 -0
- package/dist/tools/warp_grep/vercel.js.map +1 -0
- package/package.json +23 -3
- package/dist/anthropic-CknfcMoO.d.ts +0 -64
- package/dist/chunk-DF2ZOO7R.js.map +0 -1
- package/dist/client.d.ts +0 -114
- package/dist/git/client.d.ts +0 -255
- package/dist/git/config.d.ts +0 -11
- package/dist/git/index.d.ts +0 -5
- package/dist/git/types.d.ts +0 -102
- package/dist/index.d.ts +0 -14
- package/dist/modelrouter/core.d.ts +0 -56
- package/dist/modelrouter/index.d.ts +0 -2
- package/dist/modelrouter/types.d.ts +0 -35
- package/dist/openai-BkKsS30n.d.ts +0 -111
- package/dist/tools/browser/anthropic.d.ts +0 -51
- package/dist/tools/browser/core.d.ts +0 -196
- package/dist/tools/browser/index.d.ts +0 -72
- package/dist/tools/browser/openai.d.ts +0 -69
- package/dist/tools/browser/prompts.d.ts +0 -7
- package/dist/tools/browser/types.d.ts +0 -227
- package/dist/tools/browser/vercel.d.ts +0 -69
- package/dist/tools/codebase_search/anthropic.d.ts +0 -40
- package/dist/tools/codebase_search/core.d.ts +0 -40
- package/dist/tools/codebase_search/index.d.ts +0 -10
- package/dist/tools/codebase_search/openai.d.ts +0 -87
- package/dist/tools/codebase_search/prompts.d.ts +0 -7
- package/dist/tools/codebase_search/types.d.ts +0 -46
- package/dist/tools/codebase_search/vercel.d.ts +0 -65
- package/dist/tools/fastapply/anthropic.d.ts +0 -4
- package/dist/tools/fastapply/core.d.ts +0 -41
- package/dist/tools/fastapply/index.d.ts +0 -10
- package/dist/tools/fastapply/openai.d.ts +0 -4
- package/dist/tools/fastapply/prompts.d.ts +0 -7
- package/dist/tools/fastapply/types.d.ts +0 -77
- package/dist/tools/fastapply/vercel.d.ts +0 -4
- package/dist/tools/index.d.ts +0 -10
- package/dist/tools/utils/resilience.d.ts +0 -58
- package/dist/vercel-B1GZ_g9N.d.ts +0 -69
- /package/dist/{chunk-34F3D6JD.js.map → chunk-NSQGPBMU.js.map} +0 -0
|
@@ -0,0 +1,1136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// tools/warp_grep/index.ts
|
|
31
|
+
var warp_grep_exports = {};
|
|
32
|
+
__export(warp_grep_exports, {
|
|
33
|
+
AGENT_CONFIG: () => AGENT_CONFIG,
|
|
34
|
+
CommandExecProvider: () => CommandExecProvider,
|
|
35
|
+
DEFAULT_EXCLUDES: () => DEFAULT_EXCLUDES,
|
|
36
|
+
DEFAULT_MODEL: () => DEFAULT_MODEL,
|
|
37
|
+
LocalRipgrepProvider: () => LocalRipgrepProvider,
|
|
38
|
+
createAnthropicWarpGrepTool: () => createMorphWarpGrepTool2,
|
|
39
|
+
createOpenAIWarpGrepTool: () => createMorphWarpGrepTool,
|
|
40
|
+
createVercelWarpGrepTool: () => createMorphWarpGrepTool3,
|
|
41
|
+
runWarpGrep: () => runWarpGrep
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(warp_grep_exports);
|
|
44
|
+
|
|
45
|
+
// tools/warp_grep/agent/config.ts
|
|
46
|
+
var AGENT_CONFIG = {
|
|
47
|
+
// Give the model freedom; failsafe cap to prevent infinite loops
|
|
48
|
+
MAX_ROUNDS: 10,
|
|
49
|
+
TIMEOUT_MS: 3e4
|
|
50
|
+
};
|
|
51
|
+
var DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(["node_modules", ".git", "dist", "build", ".cache", "venv", "target"]);
|
|
52
|
+
var DEFAULT_MODEL = "morph-warp-grep";
|
|
53
|
+
|
|
54
|
+
// tools/warp_grep/agent/prompt.ts
|
|
55
|
+
var SYSTEM_PROMPT = `You are a code search agent. Your task is to find relevant code snippets based on a search query.
|
|
56
|
+
|
|
57
|
+
<workflow>
|
|
58
|
+
You operate in exactly 3 rounds of tool exploration, followed by a final answer:
|
|
59
|
+
|
|
60
|
+
1. In each round, you can make MULTIPLE tool calls (up to 8) to search in parallel. All tool results will be returned together after each round.
|
|
61
|
+
2. After your third round of tool calls, your next turn MUST be a single call to the \`finish\` tool with all the context you have found.
|
|
62
|
+
</workflow>
|
|
63
|
+
|
|
64
|
+
<tool_calling>
|
|
65
|
+
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
|
|
66
|
+
|
|
67
|
+
### 1. \`analyse\` - Explore Directories
|
|
68
|
+
Explore directory structure in a tree-like format.
|
|
69
|
+
**Syntax:** \`analyse <path> [pattern]\`
|
|
70
|
+
- \`<path>\`: Directory path to analyze (defaults to \`.\`)
|
|
71
|
+
- \`[pattern]\`: Optional regex pattern to filter names
|
|
72
|
+
|
|
73
|
+
For example:
|
|
74
|
+
\`\`\`
|
|
75
|
+
analyse src/api
|
|
76
|
+
analyse . "test"
|
|
77
|
+
\`\`\`
|
|
78
|
+
|
|
79
|
+
### 2. \`read\` - Read File Contents
|
|
80
|
+
Read entire files or specific line ranges.
|
|
81
|
+
**Syntax:** \`read <path>[:start-end]\`
|
|
82
|
+
- \`<path>\`: File path to read
|
|
83
|
+
- \`[:start-end]\`: Optional 1-based, inclusive line range
|
|
84
|
+
|
|
85
|
+
For example:
|
|
86
|
+
\`\`\`
|
|
87
|
+
read src/main.py
|
|
88
|
+
read src/database/connection.py:10-50
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
### 3. \`grep\` - Search with Regex
|
|
92
|
+
Search for regex patterns across files using ripgrep.
|
|
93
|
+
**Syntax:** \`grep '<pattern>' <path>\`
|
|
94
|
+
- \`'<pattern>'\`: Regex pattern (always wrap in single quotes)
|
|
95
|
+
- \`<path>\`: Directory or file to search (use \`.\` for the repo root)
|
|
96
|
+
|
|
97
|
+
For example:
|
|
98
|
+
\`\`\`
|
|
99
|
+
grep 'create_user' .
|
|
100
|
+
grep 'import.*requests' src/api
|
|
101
|
+
grep 'class\\\\s+AuthService' controllers/auth.py
|
|
102
|
+
\`\`\`
|
|
103
|
+
|
|
104
|
+
### 4. \`finish\` - Submit Final Answer
|
|
105
|
+
Submit your findings when complete.
|
|
106
|
+
**Syntax:** \`finish <file1:range1,range2...> [file2:range3...]\`
|
|
107
|
+
- Provide file paths with colon-separated, comma-separated line ranges
|
|
108
|
+
|
|
109
|
+
For example:
|
|
110
|
+
\`\`\`
|
|
111
|
+
finish src/api/auth.py:25-50,75-80 src/models/user.py:10-15
|
|
112
|
+
\`\`\`
|
|
113
|
+
</tool_calling>
|
|
114
|
+
|
|
115
|
+
<strategy>
|
|
116
|
+
- Use the \`analyse\`, \`grep\`, and \`read\` tools to gather information about the codebase.
|
|
117
|
+
- Leverage the tools smartly to make full use of their potential
|
|
118
|
+
- Make parallel tool calls within each round to investigate multiple paths or files efficiently
|
|
119
|
+
- Be systematic and thorough within your 3-round limit
|
|
120
|
+
</strategy>
|
|
121
|
+
|
|
122
|
+
<output_format>
|
|
123
|
+
- Only output tool calls themselves
|
|
124
|
+
- Do not include explanatory text, reasoning, or commentary
|
|
125
|
+
- Each tool call should be on its own line
|
|
126
|
+
- After 3 rounds of exploration, call \`finish\` with all relevant code snippets you found
|
|
127
|
+
</output_format>
|
|
128
|
+
|
|
129
|
+
Begin your exploration now to find code relevant to the query.`;
|
|
130
|
+
function getSystemPrompt() {
|
|
131
|
+
return SYSTEM_PROMPT;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// tools/warp_grep/agent/parser.ts
|
|
135
|
+
var LLMResponseParseError = class extends Error {
|
|
136
|
+
constructor(message) {
|
|
137
|
+
super(message);
|
|
138
|
+
this.name = "LLMResponseParseError";
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var LLMResponseParser = class {
|
|
142
|
+
finishSpecSplitRe = /,(?=[^,\s]+:)/;
|
|
143
|
+
parse(text) {
|
|
144
|
+
if (typeof text !== "string") {
|
|
145
|
+
throw new TypeError("Command text must be a string.");
|
|
146
|
+
}
|
|
147
|
+
const lines = text.split(/\r?\n/).map((l) => l.trim());
|
|
148
|
+
const commands = [];
|
|
149
|
+
let finishAccumulator = null;
|
|
150
|
+
lines.forEach((line, idx) => {
|
|
151
|
+
if (!line || line.startsWith("#")) return;
|
|
152
|
+
const ctx = { lineNumber: idx + 1, raw: line };
|
|
153
|
+
const parts = this.splitLine(line, ctx);
|
|
154
|
+
if (parts.length === 0) return;
|
|
155
|
+
const cmd = parts[0];
|
|
156
|
+
switch (cmd) {
|
|
157
|
+
case "analyse":
|
|
158
|
+
this.handleAnalyse(parts, ctx, commands);
|
|
159
|
+
break;
|
|
160
|
+
case "grep":
|
|
161
|
+
this.handleGrep(parts, ctx, commands);
|
|
162
|
+
break;
|
|
163
|
+
case "read":
|
|
164
|
+
this.handleRead(parts, ctx, commands);
|
|
165
|
+
break;
|
|
166
|
+
case "finish":
|
|
167
|
+
finishAccumulator = this.handleFinish(parts, ctx, finishAccumulator);
|
|
168
|
+
break;
|
|
169
|
+
default:
|
|
170
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: Unsupported command '${cmd}'`);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
if (finishAccumulator) {
|
|
174
|
+
const map = finishAccumulator;
|
|
175
|
+
const entries = [...map.entries()];
|
|
176
|
+
const filesPayload = entries.map(([path4, ranges]) => ({
|
|
177
|
+
path: path4,
|
|
178
|
+
lines: [...ranges].sort((a, b) => a[0] - b[0])
|
|
179
|
+
}));
|
|
180
|
+
commands.push({ name: "finish", arguments: { files: filesPayload } });
|
|
181
|
+
}
|
|
182
|
+
return commands;
|
|
183
|
+
}
|
|
184
|
+
splitLine(line, ctx) {
|
|
185
|
+
try {
|
|
186
|
+
const parts = [];
|
|
187
|
+
let current = "";
|
|
188
|
+
let inSingle = false;
|
|
189
|
+
for (let i = 0; i < line.length; i++) {
|
|
190
|
+
const ch = line[i];
|
|
191
|
+
if (ch === "'" && line[i - 1] !== "\\") {
|
|
192
|
+
inSingle = !inSingle;
|
|
193
|
+
current += ch;
|
|
194
|
+
} else if (!inSingle && /\s/.test(ch)) {
|
|
195
|
+
if (current) {
|
|
196
|
+
parts.push(current);
|
|
197
|
+
current = "";
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
current += ch;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (current) parts.push(current);
|
|
204
|
+
return parts;
|
|
205
|
+
} catch {
|
|
206
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: Unable to parse line.`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
handleAnalyse(parts, ctx, commands) {
|
|
210
|
+
if (parts.length < 2) {
|
|
211
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: analyse requires <path>`);
|
|
212
|
+
}
|
|
213
|
+
const path4 = parts[1];
|
|
214
|
+
const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
|
|
215
|
+
commands.push({ name: "analyse", arguments: { path: path4, pattern } });
|
|
216
|
+
}
|
|
217
|
+
// no glob tool in MCP
|
|
218
|
+
handleGrep(parts, ctx, commands) {
|
|
219
|
+
if (parts.length < 3) {
|
|
220
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep requires '<pattern>' and <path>`);
|
|
221
|
+
}
|
|
222
|
+
const pat = parts[1];
|
|
223
|
+
if (!pat.startsWith("'") || !pat.endsWith("'")) {
|
|
224
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep pattern must be single-quoted`);
|
|
225
|
+
}
|
|
226
|
+
commands.push({ name: "grep", arguments: { pattern: pat.slice(1, -1), path: parts[2] } });
|
|
227
|
+
}
|
|
228
|
+
handleRead(parts, ctx, commands) {
|
|
229
|
+
if (parts.length < 2) {
|
|
230
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: read requires <path> or <path>:<start-end>`);
|
|
231
|
+
}
|
|
232
|
+
const spec = parts[1];
|
|
233
|
+
const rangeIdx = spec.indexOf(":");
|
|
234
|
+
if (rangeIdx === -1) {
|
|
235
|
+
commands.push({ name: "read", arguments: { path: spec } });
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const path4 = spec.slice(0, rangeIdx);
|
|
239
|
+
const range = spec.slice(rangeIdx + 1);
|
|
240
|
+
const [s, e] = range.split("-").map((v) => parseInt(v, 10));
|
|
241
|
+
if (!Number.isFinite(s) || !Number.isFinite(e)) {
|
|
242
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid read range '${range}'`);
|
|
243
|
+
}
|
|
244
|
+
commands.push({ name: "read", arguments: { path: path4, start: s, end: e } });
|
|
245
|
+
}
|
|
246
|
+
handleFinish(parts, ctx, acc) {
|
|
247
|
+
const map = acc ?? /* @__PURE__ */ new Map();
|
|
248
|
+
const args = parts.slice(1);
|
|
249
|
+
for (const token of args) {
|
|
250
|
+
const [path4, rangesText] = token.split(":", 2);
|
|
251
|
+
if (!path4 || !rangesText) {
|
|
252
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid finish token '${token}'`);
|
|
253
|
+
}
|
|
254
|
+
const rangeSpecs = rangesText.split(",").filter(Boolean);
|
|
255
|
+
for (const spec of rangeSpecs) {
|
|
256
|
+
const [s, e] = spec.split("-").map((v) => parseInt(v, 10));
|
|
257
|
+
if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {
|
|
258
|
+
throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid range '${spec}'`);
|
|
259
|
+
}
|
|
260
|
+
const arr = map.get(path4) ?? [];
|
|
261
|
+
arr.push([s, e]);
|
|
262
|
+
map.set(path4, arr);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return map;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// tools/warp_grep/tools/read.ts
|
|
270
|
+
async function toolRead(provider, args) {
|
|
271
|
+
const res = await provider.read({ path: args.path, start: args.start, end: args.end });
|
|
272
|
+
return res.lines.join("\n");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// tools/warp_grep/tools/analyse.ts
|
|
276
|
+
async function toolAnalyse(provider, args) {
|
|
277
|
+
const list = await provider.analyse({
|
|
278
|
+
path: args.path,
|
|
279
|
+
pattern: args.pattern ?? null,
|
|
280
|
+
maxResults: args.maxResults ?? 100,
|
|
281
|
+
maxDepth: args.maxDepth ?? 2
|
|
282
|
+
});
|
|
283
|
+
if (!list.length) return "empty";
|
|
284
|
+
return list.map((e) => `${" ".repeat(e.depth)}- ${e.type === "dir" ? "[D]" : "[F]"} ${e.name}`).join("\n");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// tools/utils/resilience.ts
|
|
288
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
289
|
+
maxRetries: 3,
|
|
290
|
+
initialDelay: 1e3,
|
|
291
|
+
maxDelay: 3e4,
|
|
292
|
+
backoffMultiplier: 2,
|
|
293
|
+
retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
|
|
294
|
+
};
|
|
295
|
+
async function fetchWithRetry(url, options, retryConfig = {}) {
|
|
296
|
+
const {
|
|
297
|
+
maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
|
|
298
|
+
initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
|
|
299
|
+
maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
|
|
300
|
+
backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
|
|
301
|
+
retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
|
|
302
|
+
onRetry
|
|
303
|
+
} = retryConfig;
|
|
304
|
+
let lastError = null;
|
|
305
|
+
let delay = initialDelay;
|
|
306
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
307
|
+
try {
|
|
308
|
+
const response = await fetch(url, options);
|
|
309
|
+
if (response.status === 429 || response.status === 503) {
|
|
310
|
+
if (attempt < maxRetries) {
|
|
311
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
312
|
+
const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
|
|
313
|
+
const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
|
|
314
|
+
if (onRetry) {
|
|
315
|
+
onRetry(attempt + 1, error);
|
|
316
|
+
}
|
|
317
|
+
await sleep(waitTime);
|
|
318
|
+
delay *= backoffMultiplier;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return response;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
lastError = error;
|
|
325
|
+
const isRetryable = retryableErrors.some(
|
|
326
|
+
(errType) => lastError?.message?.includes(errType)
|
|
327
|
+
);
|
|
328
|
+
if (!isRetryable || attempt === maxRetries) {
|
|
329
|
+
throw lastError;
|
|
330
|
+
}
|
|
331
|
+
const waitTime = Math.min(delay, maxDelay);
|
|
332
|
+
if (onRetry) {
|
|
333
|
+
onRetry(attempt + 1, lastError);
|
|
334
|
+
}
|
|
335
|
+
await sleep(waitTime);
|
|
336
|
+
delay *= backoffMultiplier;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
throw lastError || new Error("Max retries exceeded");
|
|
340
|
+
}
|
|
341
|
+
async function withTimeout(promise, timeoutMs, errorMessage) {
|
|
342
|
+
let timeoutId;
|
|
343
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
344
|
+
timeoutId = setTimeout(() => {
|
|
345
|
+
reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
|
|
346
|
+
}, timeoutMs);
|
|
347
|
+
});
|
|
348
|
+
try {
|
|
349
|
+
const result = await Promise.race([promise, timeoutPromise]);
|
|
350
|
+
clearTimeout(timeoutId);
|
|
351
|
+
return result;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
clearTimeout(timeoutId);
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function sleep(ms) {
|
|
358
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// tools/warp_grep/agent/formatter.ts
|
|
362
|
+
var ToolOutputFormatter = class {
|
|
363
|
+
format(toolName, args, output, options = {}) {
|
|
364
|
+
const name = (toolName ?? "").trim();
|
|
365
|
+
if (!name) {
|
|
366
|
+
return "";
|
|
367
|
+
}
|
|
368
|
+
const payload = output?.toString?.()?.trim?.() ?? "";
|
|
369
|
+
const isError = Boolean(options.isError);
|
|
370
|
+
const safeArgs = args ?? {};
|
|
371
|
+
if (!payload && !isError) {
|
|
372
|
+
return "";
|
|
373
|
+
}
|
|
374
|
+
switch (name) {
|
|
375
|
+
case "read":
|
|
376
|
+
return this.formatRead(safeArgs, payload, isError);
|
|
377
|
+
case "analyse":
|
|
378
|
+
return this.formatAnalyse(safeArgs, payload, isError);
|
|
379
|
+
case "grep":
|
|
380
|
+
return this.formatGrep(safeArgs, payload, isError);
|
|
381
|
+
default:
|
|
382
|
+
return payload ? `<tool_output>
|
|
383
|
+
${payload}
|
|
384
|
+
</tool_output>` : "";
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
formatRead(args, payload, isError) {
|
|
388
|
+
if (isError) {
|
|
389
|
+
return payload;
|
|
390
|
+
}
|
|
391
|
+
const path4 = this.asString(args.path) || "...";
|
|
392
|
+
return `<file path="${path4}">
|
|
393
|
+
${payload}
|
|
394
|
+
</file>`;
|
|
395
|
+
}
|
|
396
|
+
formatAnalyse(args, payload, isError) {
|
|
397
|
+
const path4 = this.asString(args.path) || ".";
|
|
398
|
+
if (isError) {
|
|
399
|
+
return `<analyse_results path="${path4}" status="error">
|
|
400
|
+
${payload}
|
|
401
|
+
</analyse_results>`;
|
|
402
|
+
}
|
|
403
|
+
return `<analyse_results path="${path4}">
|
|
404
|
+
${payload}
|
|
405
|
+
</analyse_results>`;
|
|
406
|
+
}
|
|
407
|
+
formatGrep(args, payload, isError) {
|
|
408
|
+
const pattern = this.asString(args.pattern);
|
|
409
|
+
const path4 = this.asString(args.path);
|
|
410
|
+
const attributes = [];
|
|
411
|
+
if (pattern !== void 0) {
|
|
412
|
+
attributes.push(`pattern="${pattern}"`);
|
|
413
|
+
}
|
|
414
|
+
if (path4 !== void 0) {
|
|
415
|
+
attributes.push(`path="${path4}"`);
|
|
416
|
+
}
|
|
417
|
+
if (isError) {
|
|
418
|
+
attributes.push('status="error"');
|
|
419
|
+
}
|
|
420
|
+
const attrText = attributes.length ? ` ${attributes.join(" ")}` : "";
|
|
421
|
+
return `<grep_output${attrText}>
|
|
422
|
+
${payload}
|
|
423
|
+
</grep_output>`;
|
|
424
|
+
}
|
|
425
|
+
asString(value) {
|
|
426
|
+
if (value === null || value === void 0) {
|
|
427
|
+
return void 0;
|
|
428
|
+
}
|
|
429
|
+
return String(value);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
var sharedFormatter = new ToolOutputFormatter();
|
|
433
|
+
function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
434
|
+
return sharedFormatter.format(toolName, args, output, options);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// tools/warp_grep/agent/grep_helpers.ts
|
|
438
|
+
var GrepState = class {
|
|
439
|
+
seenLines = /* @__PURE__ */ new Set();
|
|
440
|
+
isNew(path4, lineNumber) {
|
|
441
|
+
const key = this.makeKey(path4, lineNumber);
|
|
442
|
+
return !this.seenLines.has(key);
|
|
443
|
+
}
|
|
444
|
+
add(path4, lineNumber) {
|
|
445
|
+
this.seenLines.add(this.makeKey(path4, lineNumber));
|
|
446
|
+
}
|
|
447
|
+
makeKey(path4, lineNumber) {
|
|
448
|
+
return `${path4}:${lineNumber}`;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
var MAX_GREP_OUTPUT_CHARS_PER_TURN = 6e4;
|
|
452
|
+
function extractMatchFields(payload) {
|
|
453
|
+
const text = payload.replace(/\r?\n$/, "");
|
|
454
|
+
if (!text || text.startsWith("[error]")) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
const firstSep = text.indexOf(":");
|
|
458
|
+
if (firstSep === -1) {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
let filePath = text.slice(0, firstSep).trim();
|
|
462
|
+
if (!filePath) {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
if (filePath.startsWith("./") || filePath.startsWith(".\\")) {
|
|
466
|
+
filePath = filePath.slice(2);
|
|
467
|
+
}
|
|
468
|
+
const remainder = text.slice(firstSep + 1);
|
|
469
|
+
const secondSep = remainder.indexOf(":");
|
|
470
|
+
if (secondSep === -1) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
const linePart = remainder.slice(0, secondSep);
|
|
474
|
+
const lineNumber = Number.parseInt(linePart, 10);
|
|
475
|
+
if (!Number.isInteger(lineNumber) || lineNumber <= 0) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
let contentSegment = remainder.slice(secondSep + 1);
|
|
479
|
+
const columnSep = contentSegment.indexOf(":");
|
|
480
|
+
if (columnSep !== -1 && /^\d+$/.test(contentSegment.slice(0, columnSep))) {
|
|
481
|
+
contentSegment = contentSegment.slice(columnSep + 1);
|
|
482
|
+
}
|
|
483
|
+
const content = contentSegment.trim();
|
|
484
|
+
if (!content) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
return { path: filePath, lineNumber, content };
|
|
488
|
+
}
|
|
489
|
+
function parseAndFilterGrepOutput(rawOutput, state) {
|
|
490
|
+
const matches = [];
|
|
491
|
+
if (typeof rawOutput !== "string" || !rawOutput.trim()) {
|
|
492
|
+
return matches;
|
|
493
|
+
}
|
|
494
|
+
for (const line of rawOutput.split(/\r?\n/)) {
|
|
495
|
+
const fields = extractMatchFields(line);
|
|
496
|
+
if (!fields) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (state.isNew(fields.path, fields.lineNumber)) {
|
|
500
|
+
matches.push(fields);
|
|
501
|
+
state.add(fields.path, fields.lineNumber);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return matches;
|
|
505
|
+
}
|
|
506
|
+
function truncateOutput(payload, maxChars) {
|
|
507
|
+
if (payload.length <= maxChars) {
|
|
508
|
+
return payload;
|
|
509
|
+
}
|
|
510
|
+
const note = "... (output truncated)";
|
|
511
|
+
const available = maxChars - note.length - 1;
|
|
512
|
+
if (available <= 0) {
|
|
513
|
+
return note;
|
|
514
|
+
}
|
|
515
|
+
if (payload.length <= available) {
|
|
516
|
+
return `${payload.slice(0, available).replace(/\n$/, "")}
|
|
517
|
+
${note}`;
|
|
518
|
+
}
|
|
519
|
+
const core = payload.slice(0, Math.max(0, available - 1));
|
|
520
|
+
const trimmed = core.replace(/\n$/, "").replace(/\s+$/, "");
|
|
521
|
+
const snippet = trimmed ? `${trimmed}\u2026` : "\u2026";
|
|
522
|
+
return `${snippet}
|
|
523
|
+
${note}`;
|
|
524
|
+
}
|
|
525
|
+
function formatTurnGrepOutput(matches, maxChars = MAX_GREP_OUTPUT_CHARS_PER_TURN) {
|
|
526
|
+
if (!matches || matches.length === 0) {
|
|
527
|
+
return "No new matches found.";
|
|
528
|
+
}
|
|
529
|
+
const matchesByFile = /* @__PURE__ */ new Map();
|
|
530
|
+
for (const match of matches) {
|
|
531
|
+
if (!matchesByFile.has(match.path)) {
|
|
532
|
+
matchesByFile.set(match.path, []);
|
|
533
|
+
}
|
|
534
|
+
matchesByFile.get(match.path).push(match);
|
|
535
|
+
}
|
|
536
|
+
const lines = [];
|
|
537
|
+
const sortedPaths = Array.from(matchesByFile.keys()).sort();
|
|
538
|
+
sortedPaths.forEach((filePath, index) => {
|
|
539
|
+
if (index > 0) {
|
|
540
|
+
lines.push("");
|
|
541
|
+
}
|
|
542
|
+
lines.push(filePath);
|
|
543
|
+
const sortedMatches = matchesByFile.get(filePath).slice().sort((a, b) => a.lineNumber - b.lineNumber);
|
|
544
|
+
for (const match of sortedMatches) {
|
|
545
|
+
lines.push(`${match.lineNumber}:${match.content}`);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
return truncateOutput(lines.join("\n"), maxChars);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// tools/warp_grep/tools/finish.ts
|
|
552
|
+
async function readFinishFiles(repoRoot, files, reader) {
|
|
553
|
+
const out = [];
|
|
554
|
+
for (const f of files) {
|
|
555
|
+
const ranges = mergeRanges(f.lines);
|
|
556
|
+
const chunks = [];
|
|
557
|
+
for (const [s, e] of ranges) {
|
|
558
|
+
const lines = await reader(f.path, s, e);
|
|
559
|
+
chunks.push(lines.join("\n"));
|
|
560
|
+
}
|
|
561
|
+
out.push({ path: f.path, ranges, content: chunks.join("\n") });
|
|
562
|
+
}
|
|
563
|
+
return out;
|
|
564
|
+
}
|
|
565
|
+
function mergeRanges(ranges) {
|
|
566
|
+
if (!ranges.length) return [];
|
|
567
|
+
const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
|
|
568
|
+
const merged = [];
|
|
569
|
+
let [cs, ce] = sorted[0];
|
|
570
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
571
|
+
const [s, e] = sorted[i];
|
|
572
|
+
if (s <= ce + 1) {
|
|
573
|
+
ce = Math.max(ce, e);
|
|
574
|
+
} else {
|
|
575
|
+
merged.push([cs, ce]);
|
|
576
|
+
cs = s;
|
|
577
|
+
ce = e;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
merged.push([cs, ce]);
|
|
581
|
+
return merged;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// tools/warp_grep/agent/runner.ts
|
|
585
|
+
var import_path = __toESM(require("path"), 1);
|
|
586
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
587
|
+
var parser = new LLMResponseParser();
|
|
588
|
+
async function buildInitialState(repoRoot, query) {
|
|
589
|
+
try {
|
|
590
|
+
const entries = await import_promises.default.readdir(repoRoot, { withFileTypes: true });
|
|
591
|
+
const dirs = entries.filter((e) => e.isDirectory()).map((d) => d.name).slice(0, 50);
|
|
592
|
+
const files = entries.filter((e) => e.isFile()).map((f) => f.name).slice(0, 50);
|
|
593
|
+
const parts = [
|
|
594
|
+
`<repo_root>${repoRoot}</repo_root>`,
|
|
595
|
+
`<top_dirs>${dirs.join(", ")}</top_dirs>`,
|
|
596
|
+
`<top_files>${files.join(", ")}</top_files>`
|
|
597
|
+
];
|
|
598
|
+
return parts.join("\n");
|
|
599
|
+
} catch {
|
|
600
|
+
return `<repo_root>${repoRoot}</repo_root>`;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async function callModel(messages, model, apiKey) {
|
|
604
|
+
const api = "https://api.morphllm.com/v1/chat/completions";
|
|
605
|
+
const fetchPromise = fetchWithRetry(
|
|
606
|
+
api,
|
|
607
|
+
{
|
|
608
|
+
method: "POST",
|
|
609
|
+
headers: {
|
|
610
|
+
"Content-Type": "application/json",
|
|
611
|
+
Authorization: `Bearer ${apiKey || process.env.MORPH_API_KEY || ""}`
|
|
612
|
+
},
|
|
613
|
+
body: JSON.stringify({
|
|
614
|
+
model,
|
|
615
|
+
temperature: 0,
|
|
616
|
+
max_tokens: 1024,
|
|
617
|
+
messages
|
|
618
|
+
})
|
|
619
|
+
},
|
|
620
|
+
{}
|
|
621
|
+
);
|
|
622
|
+
const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, "morph-warp-grep request timed out");
|
|
623
|
+
if (!resp.ok) {
|
|
624
|
+
const t = await resp.text();
|
|
625
|
+
throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);
|
|
626
|
+
}
|
|
627
|
+
const data = await resp.json();
|
|
628
|
+
const content = data?.choices?.[0]?.message?.content;
|
|
629
|
+
if (!content || typeof content !== "string") {
|
|
630
|
+
throw new Error("Invalid response from model");
|
|
631
|
+
}
|
|
632
|
+
return content;
|
|
633
|
+
}
|
|
634
|
+
async function runWarpGrep(config) {
|
|
635
|
+
const repoRoot = import_path.default.resolve(config.repoRoot || process.cwd());
|
|
636
|
+
const messages = [];
|
|
637
|
+
const systemMessage = { role: "system", content: getSystemPrompt() };
|
|
638
|
+
messages.push(systemMessage);
|
|
639
|
+
const queryContent = `<query>${config.query}</query>`;
|
|
640
|
+
messages.push({ role: "user", content: queryContent });
|
|
641
|
+
const initialState = await buildInitialState(repoRoot, config.query);
|
|
642
|
+
messages.push({ role: "user", content: initialState });
|
|
643
|
+
const maxRounds = AGENT_CONFIG.MAX_ROUNDS;
|
|
644
|
+
const model = config.model || DEFAULT_MODEL;
|
|
645
|
+
const provider = config.provider;
|
|
646
|
+
const errors = [];
|
|
647
|
+
const grepState = new GrepState();
|
|
648
|
+
let finishMeta;
|
|
649
|
+
let terminationReason = "terminated";
|
|
650
|
+
for (let round = 1; round <= maxRounds; round += 1) {
|
|
651
|
+
const assistantContent = await callModel(messages, model, config.apiKey).catch((e) => {
|
|
652
|
+
errors.push({ message: e instanceof Error ? e.message : String(e) });
|
|
653
|
+
return "";
|
|
654
|
+
});
|
|
655
|
+
if (!assistantContent) break;
|
|
656
|
+
messages.push({ role: "assistant", content: assistantContent });
|
|
657
|
+
let toolCalls = [];
|
|
658
|
+
try {
|
|
659
|
+
toolCalls = parser.parse(assistantContent);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
errors.push({ message: e instanceof Error ? e.message : String(e) });
|
|
662
|
+
terminationReason = "terminated";
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
if (toolCalls.length === 0) {
|
|
666
|
+
errors.push({ message: "No tool calls produced by the model." });
|
|
667
|
+
terminationReason = "terminated";
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
671
|
+
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
672
|
+
const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
|
|
673
|
+
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
674
|
+
const formatted = [];
|
|
675
|
+
const otherPromises = [];
|
|
676
|
+
for (const c of analyseCalls) {
|
|
677
|
+
const args = c.arguments ?? {};
|
|
678
|
+
otherPromises.push(
|
|
679
|
+
toolAnalyse(provider, args).then(
|
|
680
|
+
(p) => formatAgentToolOutput("analyse", args, p, { isError: false }),
|
|
681
|
+
(err) => formatAgentToolOutput("analyse", args, String(err), { isError: true })
|
|
682
|
+
)
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
for (const c of readCalls) {
|
|
686
|
+
const args = c.arguments ?? {};
|
|
687
|
+
otherPromises.push(
|
|
688
|
+
toolRead(provider, args).then(
|
|
689
|
+
(p) => formatAgentToolOutput("read", args, p, { isError: false }),
|
|
690
|
+
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
691
|
+
)
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
const otherResults = await Promise.all(otherPromises);
|
|
695
|
+
formatted.push(...otherResults);
|
|
696
|
+
for (const c of grepCalls) {
|
|
697
|
+
const args = c.arguments ?? {};
|
|
698
|
+
try {
|
|
699
|
+
const grepRes = await provider.grep({ pattern: args.pattern, path: args.path });
|
|
700
|
+
const rawOutput = Array.isArray(grepRes.lines) ? grepRes.lines.join("\n") : "";
|
|
701
|
+
const newMatches = parseAndFilterGrepOutput(rawOutput, grepState);
|
|
702
|
+
let formattedPayload = formatTurnGrepOutput(newMatches);
|
|
703
|
+
if (formattedPayload === "No new matches found.") {
|
|
704
|
+
formattedPayload = "no new matches";
|
|
705
|
+
}
|
|
706
|
+
formatted.push(formatAgentToolOutput("grep", args, formattedPayload, { isError: false }));
|
|
707
|
+
} catch (err) {
|
|
708
|
+
formatted.push(formatAgentToolOutput("grep", args, String(err), { isError: true }));
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (formatted.length > 0) {
|
|
712
|
+
messages.push({ role: "user", content: formatted.join("\n") });
|
|
713
|
+
}
|
|
714
|
+
if (finishCalls.length) {
|
|
715
|
+
const fc = finishCalls[0];
|
|
716
|
+
const files = fc.arguments?.files ?? [];
|
|
717
|
+
finishMeta = { files };
|
|
718
|
+
terminationReason = "completed";
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (terminationReason !== "completed" || !finishMeta) {
|
|
723
|
+
return { terminationReason, messages, errors };
|
|
724
|
+
}
|
|
725
|
+
const parts = ["Relevant context found:"];
|
|
726
|
+
for (const f of finishMeta.files) {
|
|
727
|
+
const ranges = f.lines.map(([s, e]) => `${s}-${e}`).join(", ");
|
|
728
|
+
parts.push(`- ${f.path}: ${ranges}`);
|
|
729
|
+
}
|
|
730
|
+
const payload = parts.join("\n");
|
|
731
|
+
const resolved = await readFinishFiles(
|
|
732
|
+
repoRoot,
|
|
733
|
+
finishMeta.files,
|
|
734
|
+
async (p, s, e) => {
|
|
735
|
+
const rr = await provider.read({ path: p, start: s, end: e });
|
|
736
|
+
return rr.lines.map((l) => {
|
|
737
|
+
const idx = l.indexOf("|");
|
|
738
|
+
return idx >= 0 ? l.slice(idx + 1) : l;
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
);
|
|
742
|
+
return {
|
|
743
|
+
terminationReason: "completed",
|
|
744
|
+
messages,
|
|
745
|
+
finish: { payload, metadata: finishMeta, resolved }
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// tools/warp_grep/providers/local.ts
|
|
750
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
751
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
752
|
+
|
|
753
|
+
// tools/warp_grep/utils/ripgrep.ts
|
|
754
|
+
var import_child_process = require("child_process");
|
|
755
|
+
function runRipgrep(args, opts) {
|
|
756
|
+
return new Promise((resolve) => {
|
|
757
|
+
const child = (0, import_child_process.spawn)("rg", args, {
|
|
758
|
+
cwd: opts?.cwd,
|
|
759
|
+
env: { ...process.env, ...opts?.env || {} },
|
|
760
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
761
|
+
});
|
|
762
|
+
let stdout = "";
|
|
763
|
+
let stderr = "";
|
|
764
|
+
child.stdout.on("data", (d) => stdout += d.toString());
|
|
765
|
+
child.stderr.on("data", (d) => stderr += d.toString());
|
|
766
|
+
child.on("close", (code) => {
|
|
767
|
+
resolve({ stdout, stderr, exitCode: typeof code === "number" ? code : -1 });
|
|
768
|
+
});
|
|
769
|
+
child.on("error", () => {
|
|
770
|
+
resolve({ stdout: "", stderr: "Failed to spawn ripgrep (rg). Ensure it is installed.", exitCode: -1 });
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// tools/warp_grep/utils/paths.ts
|
|
776
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
777
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
778
|
+
function resolveUnderRepo(repoRoot, targetPath) {
|
|
779
|
+
const absRoot = import_path2.default.resolve(repoRoot);
|
|
780
|
+
const resolved = import_path2.default.resolve(absRoot, targetPath);
|
|
781
|
+
ensureWithinRepo(absRoot, resolved);
|
|
782
|
+
return resolved;
|
|
783
|
+
}
|
|
784
|
+
function ensureWithinRepo(repoRoot, absTarget) {
|
|
785
|
+
const rel = import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absTarget));
|
|
786
|
+
if (rel.startsWith("..") || import_path2.default.isAbsolute(rel)) {
|
|
787
|
+
throw new Error(`Path outside repository root: ${absTarget}`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function toRepoRelative(repoRoot, absPath) {
|
|
791
|
+
return import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absPath));
|
|
792
|
+
}
|
|
793
|
+
function isSymlink(p) {
|
|
794
|
+
try {
|
|
795
|
+
const st = import_fs.default.lstatSync(p);
|
|
796
|
+
return st.isSymbolicLink();
|
|
797
|
+
} catch {
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
function isTextualFile(filePath, maxBytes = 2e6) {
|
|
802
|
+
try {
|
|
803
|
+
const st = import_fs.default.statSync(filePath);
|
|
804
|
+
if (!st.isFile()) return false;
|
|
805
|
+
if (st.size > maxBytes) return false;
|
|
806
|
+
const fd = import_fs.default.openSync(filePath, "r");
|
|
807
|
+
const buf = Buffer.alloc(512);
|
|
808
|
+
const read = import_fs.default.readSync(fd, buf, 0, buf.length, 0);
|
|
809
|
+
import_fs.default.closeSync(fd);
|
|
810
|
+
for (let i = 0; i < read; i++) {
|
|
811
|
+
const c = buf[i];
|
|
812
|
+
if (c === 0) return false;
|
|
813
|
+
}
|
|
814
|
+
return true;
|
|
815
|
+
} catch {
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// tools/warp_grep/utils/files.ts
|
|
821
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
822
|
+
async function readAllLines(filePath) {
|
|
823
|
+
const content = await import_promises2.default.readFile(filePath, "utf8");
|
|
824
|
+
return content.split(/\r?\n/);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// tools/warp_grep/providers/local.ts
|
|
828
|
+
var LocalRipgrepProvider = class {
|
|
829
|
+
constructor(repoRoot, excludes = DEFAULT_EXCLUDES) {
|
|
830
|
+
this.repoRoot = repoRoot;
|
|
831
|
+
this.excludes = excludes;
|
|
832
|
+
}
|
|
833
|
+
async grep(params) {
|
|
834
|
+
const abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
835
|
+
const stat = await import_promises3.default.stat(abs).catch(() => null);
|
|
836
|
+
if (!stat) return { lines: [] };
|
|
837
|
+
const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
838
|
+
const args = [
|
|
839
|
+
"--no-config",
|
|
840
|
+
"--no-heading",
|
|
841
|
+
"--with-filename",
|
|
842
|
+
"--line-number",
|
|
843
|
+
"--color=never",
|
|
844
|
+
"--trim",
|
|
845
|
+
"--max-columns=400",
|
|
846
|
+
...this.excludes.flatMap((e) => ["-g", `!${e}`]),
|
|
847
|
+
params.pattern,
|
|
848
|
+
targetArg || "."
|
|
849
|
+
];
|
|
850
|
+
const res = await runRipgrep(args, { cwd: this.repoRoot });
|
|
851
|
+
if (res.exitCode === -1) {
|
|
852
|
+
throw new Error(res.stderr || "ripgrep (rg) execution failed.");
|
|
853
|
+
}
|
|
854
|
+
if (res.exitCode !== 0 && res.exitCode !== 1) {
|
|
855
|
+
throw new Error(res.stderr || `ripgrep failed with code ${res.exitCode}`);
|
|
856
|
+
}
|
|
857
|
+
const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
858
|
+
return { lines };
|
|
859
|
+
}
|
|
860
|
+
async glob(params) {
|
|
861
|
+
const abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
862
|
+
const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
863
|
+
const args = [
|
|
864
|
+
"--no-config",
|
|
865
|
+
"--files",
|
|
866
|
+
"-g",
|
|
867
|
+
params.pattern,
|
|
868
|
+
...this.excludes.flatMap((e) => ["-g", `!${e}`]),
|
|
869
|
+
targetArg || "."
|
|
870
|
+
];
|
|
871
|
+
const res = await runRipgrep(args, { cwd: this.repoRoot });
|
|
872
|
+
if (res.exitCode === -1) {
|
|
873
|
+
throw new Error(res.stderr || "ripgrep (rg) execution failed.");
|
|
874
|
+
}
|
|
875
|
+
const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
876
|
+
return { files };
|
|
877
|
+
}
|
|
878
|
+
async read(params) {
|
|
879
|
+
const abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
880
|
+
const stat = await import_promises3.default.stat(abs).catch(() => null);
|
|
881
|
+
if (!stat || !stat.isFile()) {
|
|
882
|
+
throw new Error(`Path is not a file: ${params.path}`);
|
|
883
|
+
}
|
|
884
|
+
if (isSymlink(abs)) {
|
|
885
|
+
throw new Error(`Refusing to read symlink: ${params.path}`);
|
|
886
|
+
}
|
|
887
|
+
if (!isTextualFile(abs)) {
|
|
888
|
+
throw new Error(`Non-text or too-large file: ${params.path}`);
|
|
889
|
+
}
|
|
890
|
+
const lines = await readAllLines(abs);
|
|
891
|
+
const total = lines.length;
|
|
892
|
+
const s = params.start ?? 1;
|
|
893
|
+
const e = Math.min(params.end ?? total, total);
|
|
894
|
+
if (s > total && total > 0) {
|
|
895
|
+
throw new Error(`start ${s} exceeds file length (${total})`);
|
|
896
|
+
}
|
|
897
|
+
const out = [];
|
|
898
|
+
for (let i = s; i <= e; i += 1) {
|
|
899
|
+
const content = lines[i - 1] ?? "";
|
|
900
|
+
out.push(`${i}|${content}`);
|
|
901
|
+
}
|
|
902
|
+
return { lines: out };
|
|
903
|
+
}
|
|
904
|
+
async analyse(params) {
|
|
905
|
+
const abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
906
|
+
const stat = await import_promises3.default.stat(abs).catch(() => null);
|
|
907
|
+
if (!stat || !stat.isDirectory()) {
|
|
908
|
+
return [];
|
|
909
|
+
}
|
|
910
|
+
const maxResults = params.maxResults ?? 100;
|
|
911
|
+
const maxDepth = params.maxDepth ?? 2;
|
|
912
|
+
const regex = params.pattern ? new RegExp(params.pattern) : null;
|
|
913
|
+
const results = [];
|
|
914
|
+
async function walk(dir, depth) {
|
|
915
|
+
if (depth > maxDepth || results.length >= maxResults) return;
|
|
916
|
+
const entries = await import_promises3.default.readdir(dir, { withFileTypes: true });
|
|
917
|
+
for (const entry of entries) {
|
|
918
|
+
const full = import_path3.default.join(dir, entry.name);
|
|
919
|
+
const rel = toRepoRelative(abs, full).replace(/^[.][/\\]?/, "");
|
|
920
|
+
if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path3.default.sep).includes(ex))) continue;
|
|
921
|
+
if (regex && !regex.test(entry.name)) continue;
|
|
922
|
+
if (results.length >= maxResults) break;
|
|
923
|
+
results.push({
|
|
924
|
+
name: entry.name,
|
|
925
|
+
path: toRepoRelative(import_path3.default.resolve(""), full),
|
|
926
|
+
// relative display
|
|
927
|
+
type: entry.isDirectory() ? "dir" : "file",
|
|
928
|
+
depth
|
|
929
|
+
});
|
|
930
|
+
if (entry.isDirectory()) {
|
|
931
|
+
await walk(full, depth + 1);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
await walk(abs, 0);
|
|
936
|
+
return results;
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
// tools/warp_grep/providers/command.ts
|
|
941
|
+
var CommandExecProvider = class {
|
|
942
|
+
constructor(opts) {
|
|
943
|
+
this.opts = opts;
|
|
944
|
+
}
|
|
945
|
+
map(path4) {
|
|
946
|
+
return this.opts.pathMap ? this.opts.pathMap(path4) : path4;
|
|
947
|
+
}
|
|
948
|
+
async grep(params) {
|
|
949
|
+
const remotePath = this.map(params.path);
|
|
950
|
+
const args = [
|
|
951
|
+
"--no-config",
|
|
952
|
+
"--no-heading",
|
|
953
|
+
"--with-filename",
|
|
954
|
+
"--line-number",
|
|
955
|
+
"--color=never",
|
|
956
|
+
"--trim",
|
|
957
|
+
"--max-columns=400",
|
|
958
|
+
...(this.opts.excludes ?? DEFAULT_EXCLUDES).flatMap((e) => ["-g", `!${e}`]),
|
|
959
|
+
params.pattern,
|
|
960
|
+
remotePath || "."
|
|
961
|
+
];
|
|
962
|
+
const res = await this.opts.run("rg", args, { cwd: this.opts.cwd, env: this.opts.env });
|
|
963
|
+
if (res.exitCode === -1) throw new Error(res.stderr || "ripgrep execution failed");
|
|
964
|
+
if (res.exitCode !== 0 && res.exitCode !== 1) throw new Error(res.stderr || `ripgrep failed (${res.exitCode})`);
|
|
965
|
+
const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
966
|
+
return { lines };
|
|
967
|
+
}
|
|
968
|
+
async glob(params) {
|
|
969
|
+
const remotePath = this.map(params.path);
|
|
970
|
+
const args = [
|
|
971
|
+
"--no-config",
|
|
972
|
+
"--files",
|
|
973
|
+
"-g",
|
|
974
|
+
params.pattern,
|
|
975
|
+
...(this.opts.excludes ?? DEFAULT_EXCLUDES).flatMap((e) => ["-g", `!${e}`]),
|
|
976
|
+
remotePath || "."
|
|
977
|
+
];
|
|
978
|
+
const res = await this.opts.run("rg", args, { cwd: this.opts.cwd, env: this.opts.env });
|
|
979
|
+
if (res.exitCode === -1) throw new Error(res.stderr || "ripgrep execution failed");
|
|
980
|
+
const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
981
|
+
return { files };
|
|
982
|
+
}
|
|
983
|
+
async read(params) {
|
|
984
|
+
const remotePath = this.map(params.path);
|
|
985
|
+
const rc = this.opts.readCommand ? this.opts.readCommand(remotePath, params.start, params.end) : { cmd: "sed", args: ["-n", `${params.start ?? 1},${params.end ?? 1e6}p`, remotePath] };
|
|
986
|
+
const res = await this.opts.run(rc.cmd, rc.args, { cwd: this.opts.cwd, env: this.opts.env });
|
|
987
|
+
if (res.exitCode !== 0) throw new Error(res.stderr || `read failed (${res.exitCode})`);
|
|
988
|
+
const text = res.stdout || "";
|
|
989
|
+
const lines = text.split(/\r?\n/).map((line, idx) => `${(params.start ?? 1) + idx}|${line}`);
|
|
990
|
+
return { lines: lines.filter((l) => l !== `${(params.start ?? 1) + (lines.length - 1)}|`) };
|
|
991
|
+
}
|
|
992
|
+
async analyse(params) {
|
|
993
|
+
const target = this.map(params.path);
|
|
994
|
+
const pattern = params.pattern ?? "*";
|
|
995
|
+
const files = await this.glob({ pattern, path: target }).catch(() => ({ files: [] }));
|
|
996
|
+
return files.files.slice(0, params.maxResults ?? 100).map((f) => ({
|
|
997
|
+
name: f.split("/").pop() || f,
|
|
998
|
+
path: f,
|
|
999
|
+
type: f.endsWith("/") ? "dir" : "file",
|
|
1000
|
+
depth: 0
|
|
1001
|
+
}));
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// tools/warp_grep/openai.ts
|
|
1006
|
+
var import_zod = require("zod");
|
|
1007
|
+
var INPUT_SCHEMA = import_zod.z.object({
|
|
1008
|
+
query: import_zod.z.string().describe("Free-form repository question")
|
|
1009
|
+
});
|
|
1010
|
+
function createMorphWarpGrepTool(config) {
|
|
1011
|
+
const tool2 = {
|
|
1012
|
+
type: "function",
|
|
1013
|
+
function: {
|
|
1014
|
+
name: "morph-warp-grep",
|
|
1015
|
+
description: "A fast and accurate tool that can search for all relevant context in a codebase. You must use this tool to save time and avoid context pollution.",
|
|
1016
|
+
parameters: {
|
|
1017
|
+
type: "object",
|
|
1018
|
+
properties: {
|
|
1019
|
+
query: { type: "string", description: "Free-form repository question" }
|
|
1020
|
+
},
|
|
1021
|
+
required: ["query"]
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
return Object.assign(tool2, {
|
|
1026
|
+
execute: async (input) => {
|
|
1027
|
+
const parsed = INPUT_SCHEMA.parse(typeof input === "string" ? JSON.parse(input) : input);
|
|
1028
|
+
const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
|
|
1029
|
+
const result = await runWarpGrep({
|
|
1030
|
+
query: parsed.query,
|
|
1031
|
+
repoRoot: config.repoRoot,
|
|
1032
|
+
provider,
|
|
1033
|
+
excludes: config.excludes,
|
|
1034
|
+
includes: config.includes,
|
|
1035
|
+
debug: config.debug ?? false,
|
|
1036
|
+
apiKey: config.apiKey
|
|
1037
|
+
});
|
|
1038
|
+
if (result.terminationReason !== "completed" || !result.finish?.metadata) {
|
|
1039
|
+
return { success: false, error: "Search did not complete", messages: result.messages };
|
|
1040
|
+
}
|
|
1041
|
+
const contexts = (result.finish.resolved || []).map((r) => ({
|
|
1042
|
+
file: r.path,
|
|
1043
|
+
content: r.content
|
|
1044
|
+
}));
|
|
1045
|
+
return { success: true, contexts, summary: result.finish.payload };
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// tools/warp_grep/anthropic.ts
|
|
1051
|
+
var import_zod2 = require("zod");
|
|
1052
|
+
var INPUT_SCHEMA2 = import_zod2.z.object({
|
|
1053
|
+
query: import_zod2.z.string().describe("Free-form repository question")
|
|
1054
|
+
});
|
|
1055
|
+
function createMorphWarpGrepTool2(config) {
|
|
1056
|
+
const tool2 = {
|
|
1057
|
+
name: "morph-warp-grep",
|
|
1058
|
+
description: "A fast and accurate tool that can search for all relevant context in a codebase. You must use this tool to save time and avoid context pollution.",
|
|
1059
|
+
input_schema: {
|
|
1060
|
+
type: "object",
|
|
1061
|
+
properties: {
|
|
1062
|
+
query: { type: "string", description: "Free-form repository question" }
|
|
1063
|
+
},
|
|
1064
|
+
required: ["query"]
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
return Object.assign(tool2, {
|
|
1068
|
+
execute: async (input) => {
|
|
1069
|
+
const parsed = INPUT_SCHEMA2.parse(typeof input === "string" ? JSON.parse(input) : input);
|
|
1070
|
+
const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
|
|
1071
|
+
const result = await runWarpGrep({
|
|
1072
|
+
query: parsed.query,
|
|
1073
|
+
repoRoot: config.repoRoot,
|
|
1074
|
+
provider,
|
|
1075
|
+
excludes: config.excludes,
|
|
1076
|
+
includes: config.includes,
|
|
1077
|
+
debug: config.debug ?? false,
|
|
1078
|
+
apiKey: config.apiKey
|
|
1079
|
+
});
|
|
1080
|
+
if (result.terminationReason !== "completed" || !result.finish?.metadata) {
|
|
1081
|
+
return { success: false, error: "Search did not complete", messages: result.messages };
|
|
1082
|
+
}
|
|
1083
|
+
const contexts = (result.finish.resolved || []).map((r) => ({
|
|
1084
|
+
file: r.path,
|
|
1085
|
+
content: r.content
|
|
1086
|
+
}));
|
|
1087
|
+
return { success: true, contexts, summary: result.finish.payload };
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// tools/warp_grep/vercel.ts
|
|
1093
|
+
var import_ai = require("ai");
|
|
1094
|
+
var import_zod3 = require("zod");
|
|
1095
|
+
function createMorphWarpGrepTool3(config) {
|
|
1096
|
+
const schema = import_zod3.z.object({
|
|
1097
|
+
query: import_zod3.z.string().describe("Free-form repository question")
|
|
1098
|
+
});
|
|
1099
|
+
return (0, import_ai.tool)({
|
|
1100
|
+
description: "A fast and accurate tool that can search for all relevant context in a codebase. You must use this tool to save time and avoid context pollution.",
|
|
1101
|
+
inputSchema: schema,
|
|
1102
|
+
execute: async (params) => {
|
|
1103
|
+
const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
|
|
1104
|
+
const result = await runWarpGrep({
|
|
1105
|
+
query: params.query,
|
|
1106
|
+
repoRoot: config.repoRoot,
|
|
1107
|
+
provider,
|
|
1108
|
+
excludes: config.excludes,
|
|
1109
|
+
includes: config.includes,
|
|
1110
|
+
debug: config.debug ?? false,
|
|
1111
|
+
apiKey: config.apiKey
|
|
1112
|
+
});
|
|
1113
|
+
if (result.terminationReason !== "completed" || !result.finish?.metadata) {
|
|
1114
|
+
return { success: false, error: "Search did not complete", messages: result.messages };
|
|
1115
|
+
}
|
|
1116
|
+
const contexts = (result.finish.resolved || []).map((r) => ({
|
|
1117
|
+
file: r.path,
|
|
1118
|
+
content: r.content
|
|
1119
|
+
}));
|
|
1120
|
+
return { success: true, contexts, summary: result.finish.payload };
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1125
|
+
0 && (module.exports = {
|
|
1126
|
+
AGENT_CONFIG,
|
|
1127
|
+
CommandExecProvider,
|
|
1128
|
+
DEFAULT_EXCLUDES,
|
|
1129
|
+
DEFAULT_MODEL,
|
|
1130
|
+
LocalRipgrepProvider,
|
|
1131
|
+
createAnthropicWarpGrepTool,
|
|
1132
|
+
createOpenAIWarpGrepTool,
|
|
1133
|
+
createVercelWarpGrepTool,
|
|
1134
|
+
runWarpGrep
|
|
1135
|
+
});
|
|
1136
|
+
//# sourceMappingURL=index.cjs.map
|