@mindstudio-ai/remy 0.1.232 → 0.1.234
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/automatedActions/publish.md +2 -2
- package/dist/headless.js +113 -104
- package/dist/index.js +119 -106
- package/package.json +1 -1
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
This is an automated action triggered by the user pressing "Publish" in the editor.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Pressing Publish is the user's decision to ship. The work is finished, and they've watched it come together in the preview throughout the session — now they're asking you to deploy it to `main` (which triggers a production build). Your job is to describe what's going out and ship it.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Read what's changed since the last push — the diffs and commits — and turn it into a user-friendly changelog with `presentPublishPlan`: a plain-language summary of what's new ("added vendor approval workflow", "fixed invoice totals", "updated the dashboard layout"). Reference specific code or file paths only when it helps clarity. This is what the user sees before deploying.
|
|
10
10
|
|
|
11
11
|
If approved:
|
|
12
12
|
- Stage and commit any uncommitted changes with a clean, descriptive commit message. If the committed work resolves any open issues (`mindstudio-prod issues`), reference them in the commit message with a closing keyword — `fixes #42`, `closes #7` — so the deploy closes them automatically once it goes live.
|
package/dist/headless.js
CHANGED
|
@@ -478,7 +478,8 @@ var ALLOWED_MODELS_BY_TYPE = {
|
|
|
478
478
|
"glm-5.2",
|
|
479
479
|
"muse-spark-1.1",
|
|
480
480
|
"kimi-k2-7-code",
|
|
481
|
-
"kimi-k3"
|
|
481
|
+
"kimi-k3",
|
|
482
|
+
"deepseek-v4-flash-0731"
|
|
482
483
|
]
|
|
483
484
|
// vision: undefined — unconstrained
|
|
484
485
|
// image_generation: undefined — unconstrained
|
|
@@ -1894,7 +1895,7 @@ var compactConversationTool = {
|
|
|
1894
1895
|
|
|
1895
1896
|
// src/tools/code/readFile.ts
|
|
1896
1897
|
import fs12 from "fs/promises";
|
|
1897
|
-
var
|
|
1898
|
+
var DEFAULT_WINDOW = 500;
|
|
1898
1899
|
function isBinary(buffer) {
|
|
1899
1900
|
const sample = buffer.subarray(0, 8192);
|
|
1900
1901
|
for (let i = 0; i < sample.length; i++) {
|
|
@@ -1908,7 +1909,7 @@ var readFileTool = {
|
|
|
1908
1909
|
clearable: true,
|
|
1909
1910
|
definition: {
|
|
1910
1911
|
name: "readFile",
|
|
1911
|
-
description: "Read a file's contents with line numbers. Always read a file before editing it \u2014 never guess at contents.
|
|
1912
|
+
description: "Read a file's contents with line numbers. Always read a file before editing it \u2014 never guess at contents. By default returns the first 500 lines. To read a specific range, pass startLine and endLine (1-indexed, inclusive) \u2014 e.g. to read lines 253\u2013343, pass startLine: 253, endLine: 343. To read the end of a file or log, pass tail (the number of lines from the end). Line numbers in the output correspond to what editFile expects. For a large file, locate the relevant section first (symbols or grep), then read just that range.",
|
|
1912
1913
|
inputSchema: {
|
|
1913
1914
|
type: "object",
|
|
1914
1915
|
properties: {
|
|
@@ -1916,13 +1917,17 @@ var readFileTool = {
|
|
|
1916
1917
|
type: "string",
|
|
1917
1918
|
description: "The file path to read, relative to the project root."
|
|
1918
1919
|
},
|
|
1919
|
-
|
|
1920
|
+
startLine: {
|
|
1920
1921
|
type: "number",
|
|
1921
|
-
description: "
|
|
1922
|
+
description: "First line to read (1-indexed, inclusive). Defaults to 1. Pair with endLine to read an exact range \u2014 e.g. startLine: 253, endLine: 343 reads lines 253\u2013343."
|
|
1922
1923
|
},
|
|
1923
|
-
|
|
1924
|
+
endLine: {
|
|
1924
1925
|
type: "number",
|
|
1925
|
-
description: "
|
|
1926
|
+
description: "Last line to read (1-indexed, inclusive). Defaults to a 500-line window from startLine, capped at the end of the file. Use with startLine to read an exact range."
|
|
1927
|
+
},
|
|
1928
|
+
tail: {
|
|
1929
|
+
type: "number",
|
|
1930
|
+
description: "Read only the last N lines of the file (useful for logs). When set, startLine and endLine are ignored."
|
|
1926
1931
|
}
|
|
1927
1932
|
},
|
|
1928
1933
|
required: ["path"]
|
|
@@ -1939,22 +1944,37 @@ var readFileTool = {
|
|
|
1939
1944
|
const content = buffer.toString("utf-8");
|
|
1940
1945
|
const allLines = content.split("\n");
|
|
1941
1946
|
const totalLines = allLines.length;
|
|
1942
|
-
const
|
|
1947
|
+
const tail = input.tail != null ? Math.floor(Number(input.tail)) : void 0;
|
|
1943
1948
|
let startIdx;
|
|
1944
|
-
|
|
1945
|
-
|
|
1949
|
+
let endIdxExclusive;
|
|
1950
|
+
if (tail != null && tail > 0) {
|
|
1951
|
+
startIdx = Math.max(0, totalLines - tail);
|
|
1952
|
+
endIdxExclusive = totalLines;
|
|
1946
1953
|
} else {
|
|
1947
|
-
|
|
1954
|
+
const startLine = Math.max(1, Math.floor(Number(input.startLine) || 1));
|
|
1955
|
+
startIdx = startLine - 1;
|
|
1956
|
+
if (startIdx >= totalLines) {
|
|
1957
|
+
return `${input.path} has ${totalLines} lines \u2014 startLine ${startLine} is past the end of the file.`;
|
|
1958
|
+
}
|
|
1959
|
+
if (input.endLine != null) {
|
|
1960
|
+
const endLine = Math.min(
|
|
1961
|
+
totalLines,
|
|
1962
|
+
Math.max(startLine, Math.floor(Number(input.endLine)))
|
|
1963
|
+
);
|
|
1964
|
+
endIdxExclusive = endLine;
|
|
1965
|
+
} else {
|
|
1966
|
+
endIdxExclusive = Math.min(startIdx + DEFAULT_WINDOW, totalLines);
|
|
1967
|
+
}
|
|
1948
1968
|
}
|
|
1949
|
-
const sliced = allLines.slice(startIdx,
|
|
1969
|
+
const sliced = allLines.slice(startIdx, endIdxExclusive);
|
|
1950
1970
|
const numbered = sliced.map((line, i) => `${String(startIdx + i + 1).padStart(4)} ${line}`).join("\n");
|
|
1951
1971
|
let result = numbered;
|
|
1952
|
-
const endLine = startIdx + sliced.length;
|
|
1953
1972
|
const displayStart = startIdx + 1;
|
|
1954
|
-
|
|
1973
|
+
const displayEnd = startIdx + sliced.length;
|
|
1974
|
+
if (displayStart > 1 || displayEnd < totalLines) {
|
|
1955
1975
|
result += `
|
|
1956
1976
|
|
|
1957
|
-
(showing lines ${displayStart}\u2013${
|
|
1977
|
+
(showing lines ${displayStart}\u2013${displayEnd} of ${totalLines} \u2014 pass startLine/endLine to read a different range)`;
|
|
1958
1978
|
}
|
|
1959
1979
|
return result;
|
|
1960
1980
|
} catch (err) {
|
|
@@ -2122,7 +2142,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2122
2142
|
// src/tools/code/bash.ts
|
|
2123
2143
|
import { spawn as spawn2 } from "child_process";
|
|
2124
2144
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
2125
|
-
var
|
|
2145
|
+
var DEFAULT_MAX_LINES2 = 500;
|
|
2126
2146
|
var MAX_OUTPUT_BYTES = 3e4;
|
|
2127
2147
|
var bashTool = {
|
|
2128
2148
|
clearable: true,
|
|
@@ -2153,7 +2173,7 @@ var bashTool = {
|
|
|
2153
2173
|
}
|
|
2154
2174
|
},
|
|
2155
2175
|
async execute(input, context) {
|
|
2156
|
-
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines ||
|
|
2176
|
+
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES2;
|
|
2157
2177
|
const timeoutMs = input.timeout ? input.timeout * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
2158
2178
|
return new Promise((resolve2) => {
|
|
2159
2179
|
const child = spawn2("sh", ["-c", input.command], {
|
|
@@ -2226,8 +2246,16 @@ var bashTool = {
|
|
|
2226
2246
|
// src/tools/code/grep.ts
|
|
2227
2247
|
import { exec } from "child_process";
|
|
2228
2248
|
var DEFAULT_MAX = 50;
|
|
2229
|
-
function
|
|
2230
|
-
const
|
|
2249
|
+
function clampContext(v) {
|
|
2250
|
+
const n = Math.floor(Number(v));
|
|
2251
|
+
return Number.isFinite(n) ? Math.min(100, Math.max(0, n)) : 0;
|
|
2252
|
+
}
|
|
2253
|
+
function formatResults(stdout, max, mode) {
|
|
2254
|
+
const trimmed = stdout.trim();
|
|
2255
|
+
if (mode !== "content") {
|
|
2256
|
+
return trimmed;
|
|
2257
|
+
}
|
|
2258
|
+
const lines = trimmed.split("\n");
|
|
2231
2259
|
let result = lines.join("\n");
|
|
2232
2260
|
if (lines.length >= max) {
|
|
2233
2261
|
result += `
|
|
@@ -2240,7 +2268,7 @@ var grepTool = {
|
|
|
2240
2268
|
clearable: true,
|
|
2241
2269
|
definition: {
|
|
2242
2270
|
name: "grep",
|
|
2243
|
-
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
2271
|
+
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. Set outputMode to 'count' for per-file match counts (like grep -c) or 'filesWithMatches' for just the file paths (like grep -l). Add context (like grep -C), or contextBefore/contextAfter (like grep -B/-A), to include surrounding lines. Set caseInsensitive (like grep -i) for a case-insensitive search. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
2244
2272
|
inputSchema: {
|
|
2245
2273
|
type: "object",
|
|
2246
2274
|
properties: {
|
|
@@ -2259,6 +2287,27 @@ var grepTool = {
|
|
|
2259
2287
|
maxResults: {
|
|
2260
2288
|
type: "number",
|
|
2261
2289
|
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
2290
|
+
},
|
|
2291
|
+
outputMode: {
|
|
2292
|
+
type: "string",
|
|
2293
|
+
enum: ["content", "count", "filesWithMatches"],
|
|
2294
|
+
description: "What to return. 'content' (default): matching lines with line numbers. 'count': number of matches per file, like grep -c. 'filesWithMatches': just the paths of files that contain a match, like grep -l."
|
|
2295
|
+
},
|
|
2296
|
+
context: {
|
|
2297
|
+
type: "number",
|
|
2298
|
+
description: "Lines of context to show before AND after each match, like grep -C. Content mode only."
|
|
2299
|
+
},
|
|
2300
|
+
contextBefore: {
|
|
2301
|
+
type: "number",
|
|
2302
|
+
description: "Lines of context before each match, like grep -B. Content mode only; ignored if context is set."
|
|
2303
|
+
},
|
|
2304
|
+
contextAfter: {
|
|
2305
|
+
type: "number",
|
|
2306
|
+
description: "Lines of context after each match, like grep -A. Content mode only; ignored if context is set."
|
|
2307
|
+
},
|
|
2308
|
+
caseInsensitive: {
|
|
2309
|
+
type: "boolean",
|
|
2310
|
+
description: "Case-insensitive search, like grep -i."
|
|
2262
2311
|
}
|
|
2263
2312
|
},
|
|
2264
2313
|
required: ["pattern"]
|
|
@@ -2266,20 +2315,55 @@ var grepTool = {
|
|
|
2266
2315
|
},
|
|
2267
2316
|
async execute(input) {
|
|
2268
2317
|
const searchPath = input.path || ".";
|
|
2269
|
-
const max =
|
|
2318
|
+
const max = Math.max(
|
|
2319
|
+
1,
|
|
2320
|
+
Math.floor(Number(input.maxResults) || DEFAULT_MAX)
|
|
2321
|
+
);
|
|
2270
2322
|
const globFlag = input.glob ? ` --glob '${input.glob}'` : "";
|
|
2271
2323
|
const escaped = input.pattern.replace(/'/g, "'\\''");
|
|
2272
|
-
const
|
|
2273
|
-
const
|
|
2324
|
+
const mode = input.outputMode === "count" || input.outputMode === "filesWithMatches" ? input.outputMode : "content";
|
|
2325
|
+
const ci = input.caseInsensitive ? " -i" : "";
|
|
2326
|
+
let ctx = "";
|
|
2327
|
+
if (mode === "content") {
|
|
2328
|
+
if (input.context != null) {
|
|
2329
|
+
const c = clampContext(input.context);
|
|
2330
|
+
if (c > 0) {
|
|
2331
|
+
ctx = ` -C ${c}`;
|
|
2332
|
+
}
|
|
2333
|
+
} else {
|
|
2334
|
+
const b = input.contextBefore != null ? clampContext(input.contextBefore) : 0;
|
|
2335
|
+
const a = input.contextAfter != null ? clampContext(input.contextAfter) : 0;
|
|
2336
|
+
if (b > 0) {
|
|
2337
|
+
ctx += ` -B ${b}`;
|
|
2338
|
+
}
|
|
2339
|
+
if (a > 0) {
|
|
2340
|
+
ctx += ` -A ${a}`;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
let rgFlags;
|
|
2345
|
+
let grepFlags;
|
|
2346
|
+
if (mode === "count") {
|
|
2347
|
+
rgFlags = `--count${ci}`;
|
|
2348
|
+
grepFlags = `-rc${ci}`;
|
|
2349
|
+
} else if (mode === "filesWithMatches") {
|
|
2350
|
+
rgFlags = `-l${ci}`;
|
|
2351
|
+
grepFlags = `-rl${ci}`;
|
|
2352
|
+
} else {
|
|
2353
|
+
rgFlags = `-n --no-heading${ci}${ctx} --max-count=${max}`;
|
|
2354
|
+
grepFlags = `-rn${ci}${ctx} --max-count=${max}`;
|
|
2355
|
+
}
|
|
2356
|
+
const rgCmd = `rg ${rgFlags}${globFlag} '${escaped}' ${searchPath}`;
|
|
2357
|
+
const grepCmd = `grep ${grepFlags} '${escaped}' ${searchPath} --include='*.ts' --include='*.tsx' --include='*.js' --include='*.json' --include='*.md'`;
|
|
2274
2358
|
return new Promise((resolve2) => {
|
|
2275
2359
|
exec(rgCmd, { maxBuffer: 512 * 1024 }, (err, stdout) => {
|
|
2276
2360
|
if (stdout?.trim()) {
|
|
2277
|
-
resolve2(formatResults(stdout, max));
|
|
2361
|
+
resolve2(formatResults(stdout, max, mode));
|
|
2278
2362
|
return;
|
|
2279
2363
|
}
|
|
2280
2364
|
exec(grepCmd, { maxBuffer: 512 * 1024 }, (_err, grepStdout) => {
|
|
2281
2365
|
if (grepStdout?.trim()) {
|
|
2282
|
-
resolve2(formatResults(grepStdout, max));
|
|
2366
|
+
resolve2(formatResults(grepStdout, max, mode));
|
|
2283
2367
|
} else {
|
|
2284
2368
|
resolve2("No matches found.");
|
|
2285
2369
|
}
|
|
@@ -3959,85 +4043,10 @@ var screenshotTool = {
|
|
|
3959
4043
|
|
|
3960
4044
|
// src/subagents/common/tools.ts
|
|
3961
4045
|
var COMMON_READ_TOOLS = [
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
type: "object",
|
|
3967
|
-
properties: {
|
|
3968
|
-
path: {
|
|
3969
|
-
type: "string",
|
|
3970
|
-
description: "The file path to read, relative to the project root."
|
|
3971
|
-
},
|
|
3972
|
-
offset: {
|
|
3973
|
-
type: "number",
|
|
3974
|
-
description: "Line number to start reading from (1-indexed). Use a negative number to read from the end (e.g., -50 reads the last 50 lines). Defaults to 1."
|
|
3975
|
-
},
|
|
3976
|
-
maxLines: {
|
|
3977
|
-
type: "number",
|
|
3978
|
-
description: "Maximum number of lines to return. Defaults to 500. Set to 0 for no limit."
|
|
3979
|
-
}
|
|
3980
|
-
},
|
|
3981
|
-
required: ["path"]
|
|
3982
|
-
}
|
|
3983
|
-
},
|
|
3984
|
-
{
|
|
3985
|
-
name: "listDir",
|
|
3986
|
-
description: "List the contents of a directory with one level of subdirectory expansion. Shows file sizes and collapses single-child directory chains (a/b/c/ shown as one entry). Use this for a quick overview of a directory's structure. For finding files across the whole project, use glob instead.",
|
|
3987
|
-
inputSchema: {
|
|
3988
|
-
type: "object",
|
|
3989
|
-
properties: {
|
|
3990
|
-
path: {
|
|
3991
|
-
type: "string",
|
|
3992
|
-
description: 'Directory path to list, relative to project root. Defaults to ".".'
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3996
|
-
},
|
|
3997
|
-
{
|
|
3998
|
-
name: "grep",
|
|
3999
|
-
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
4000
|
-
inputSchema: {
|
|
4001
|
-
type: "object",
|
|
4002
|
-
properties: {
|
|
4003
|
-
pattern: {
|
|
4004
|
-
type: "string",
|
|
4005
|
-
description: "The search pattern (regex supported)."
|
|
4006
|
-
},
|
|
4007
|
-
path: {
|
|
4008
|
-
type: "string",
|
|
4009
|
-
description: "Directory or file to search in. Defaults to current directory."
|
|
4010
|
-
},
|
|
4011
|
-
glob: {
|
|
4012
|
-
type: "string",
|
|
4013
|
-
description: 'File glob to filter (e.g., "*.ts"). Only used with ripgrep.'
|
|
4014
|
-
},
|
|
4015
|
-
maxResults: {
|
|
4016
|
-
type: "number",
|
|
4017
|
-
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
4018
|
-
}
|
|
4019
|
-
},
|
|
4020
|
-
required: ["pattern"]
|
|
4021
|
-
}
|
|
4022
|
-
},
|
|
4023
|
-
{
|
|
4024
|
-
name: "glob",
|
|
4025
|
-
description: 'Find files matching a glob pattern. Returns matching file paths sorted alphabetically (default 200 results). Use this to discover project structure, find files by name or extension, or check if a file exists. Common patterns: "**/*.ts" (all TypeScript files), "src/**/*.tsx" (React components in src), "*.json" (root-level JSON files). Automatically excludes node_modules and .git.',
|
|
4026
|
-
inputSchema: {
|
|
4027
|
-
type: "object",
|
|
4028
|
-
properties: {
|
|
4029
|
-
pattern: {
|
|
4030
|
-
type: "string",
|
|
4031
|
-
description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json").'
|
|
4032
|
-
},
|
|
4033
|
-
maxResults: {
|
|
4034
|
-
type: "number",
|
|
4035
|
-
description: "Maximum number of file paths to return. Defaults to 200. Increase if you need the complete list."
|
|
4036
|
-
}
|
|
4037
|
-
},
|
|
4038
|
-
required: ["pattern"]
|
|
4039
|
-
}
|
|
4040
|
-
}
|
|
4046
|
+
readFileTool.definition,
|
|
4047
|
+
listDirTool.definition,
|
|
4048
|
+
grepTool.definition,
|
|
4049
|
+
globTool.definition
|
|
4041
4050
|
];
|
|
4042
4051
|
var COMMON_READ_TOOL_NAMES = new Set(
|
|
4043
4052
|
COMMON_READ_TOOLS.map((t) => t.name)
|
package/dist/index.js
CHANGED
|
@@ -2094,7 +2094,8 @@ var init_surfaces = __esm({
|
|
|
2094
2094
|
"glm-5.2",
|
|
2095
2095
|
"muse-spark-1.1",
|
|
2096
2096
|
"kimi-k2-7-code",
|
|
2097
|
-
"kimi-k3"
|
|
2097
|
+
"kimi-k3",
|
|
2098
|
+
"deepseek-v4-flash-0731"
|
|
2098
2099
|
]
|
|
2099
2100
|
// vision: undefined — unconstrained
|
|
2100
2101
|
// image_generation: undefined — unconstrained
|
|
@@ -2408,16 +2409,16 @@ function isBinary(buffer) {
|
|
|
2408
2409
|
}
|
|
2409
2410
|
return false;
|
|
2410
2411
|
}
|
|
2411
|
-
var
|
|
2412
|
+
var DEFAULT_WINDOW, readFileTool;
|
|
2412
2413
|
var init_readFile = __esm({
|
|
2413
2414
|
"src/tools/code/readFile.ts"() {
|
|
2414
2415
|
"use strict";
|
|
2415
|
-
|
|
2416
|
+
DEFAULT_WINDOW = 500;
|
|
2416
2417
|
readFileTool = {
|
|
2417
2418
|
clearable: true,
|
|
2418
2419
|
definition: {
|
|
2419
2420
|
name: "readFile",
|
|
2420
|
-
description: "Read a file's contents with line numbers. Always read a file before editing it \u2014 never guess at contents.
|
|
2421
|
+
description: "Read a file's contents with line numbers. Always read a file before editing it \u2014 never guess at contents. By default returns the first 500 lines. To read a specific range, pass startLine and endLine (1-indexed, inclusive) \u2014 e.g. to read lines 253\u2013343, pass startLine: 253, endLine: 343. To read the end of a file or log, pass tail (the number of lines from the end). Line numbers in the output correspond to what editFile expects. For a large file, locate the relevant section first (symbols or grep), then read just that range.",
|
|
2421
2422
|
inputSchema: {
|
|
2422
2423
|
type: "object",
|
|
2423
2424
|
properties: {
|
|
@@ -2425,13 +2426,17 @@ var init_readFile = __esm({
|
|
|
2425
2426
|
type: "string",
|
|
2426
2427
|
description: "The file path to read, relative to the project root."
|
|
2427
2428
|
},
|
|
2428
|
-
|
|
2429
|
+
startLine: {
|
|
2429
2430
|
type: "number",
|
|
2430
|
-
description: "
|
|
2431
|
+
description: "First line to read (1-indexed, inclusive). Defaults to 1. Pair with endLine to read an exact range \u2014 e.g. startLine: 253, endLine: 343 reads lines 253\u2013343."
|
|
2431
2432
|
},
|
|
2432
|
-
|
|
2433
|
+
endLine: {
|
|
2433
2434
|
type: "number",
|
|
2434
|
-
description: "
|
|
2435
|
+
description: "Last line to read (1-indexed, inclusive). Defaults to a 500-line window from startLine, capped at the end of the file. Use with startLine to read an exact range."
|
|
2436
|
+
},
|
|
2437
|
+
tail: {
|
|
2438
|
+
type: "number",
|
|
2439
|
+
description: "Read only the last N lines of the file (useful for logs). When set, startLine and endLine are ignored."
|
|
2435
2440
|
}
|
|
2436
2441
|
},
|
|
2437
2442
|
required: ["path"]
|
|
@@ -2448,22 +2453,37 @@ var init_readFile = __esm({
|
|
|
2448
2453
|
const content = buffer.toString("utf-8");
|
|
2449
2454
|
const allLines = content.split("\n");
|
|
2450
2455
|
const totalLines = allLines.length;
|
|
2451
|
-
const
|
|
2456
|
+
const tail = input.tail != null ? Math.floor(Number(input.tail)) : void 0;
|
|
2452
2457
|
let startIdx;
|
|
2453
|
-
|
|
2454
|
-
|
|
2458
|
+
let endIdxExclusive;
|
|
2459
|
+
if (tail != null && tail > 0) {
|
|
2460
|
+
startIdx = Math.max(0, totalLines - tail);
|
|
2461
|
+
endIdxExclusive = totalLines;
|
|
2455
2462
|
} else {
|
|
2456
|
-
|
|
2463
|
+
const startLine = Math.max(1, Math.floor(Number(input.startLine) || 1));
|
|
2464
|
+
startIdx = startLine - 1;
|
|
2465
|
+
if (startIdx >= totalLines) {
|
|
2466
|
+
return `${input.path} has ${totalLines} lines \u2014 startLine ${startLine} is past the end of the file.`;
|
|
2467
|
+
}
|
|
2468
|
+
if (input.endLine != null) {
|
|
2469
|
+
const endLine = Math.min(
|
|
2470
|
+
totalLines,
|
|
2471
|
+
Math.max(startLine, Math.floor(Number(input.endLine)))
|
|
2472
|
+
);
|
|
2473
|
+
endIdxExclusive = endLine;
|
|
2474
|
+
} else {
|
|
2475
|
+
endIdxExclusive = Math.min(startIdx + DEFAULT_WINDOW, totalLines);
|
|
2476
|
+
}
|
|
2457
2477
|
}
|
|
2458
|
-
const sliced = allLines.slice(startIdx,
|
|
2478
|
+
const sliced = allLines.slice(startIdx, endIdxExclusive);
|
|
2459
2479
|
const numbered = sliced.map((line, i) => `${String(startIdx + i + 1).padStart(4)} ${line}`).join("\n");
|
|
2460
2480
|
let result = numbered;
|
|
2461
|
-
const endLine = startIdx + sliced.length;
|
|
2462
2481
|
const displayStart = startIdx + 1;
|
|
2463
|
-
|
|
2482
|
+
const displayEnd = startIdx + sliced.length;
|
|
2483
|
+
if (displayStart > 1 || displayEnd < totalLines) {
|
|
2464
2484
|
result += `
|
|
2465
2485
|
|
|
2466
|
-
(showing lines ${displayStart}\u2013${
|
|
2486
|
+
(showing lines ${displayStart}\u2013${displayEnd} of ${totalLines} \u2014 pass startLine/endLine to read a different range)`;
|
|
2467
2487
|
}
|
|
2468
2488
|
return result;
|
|
2469
2489
|
} catch (err) {
|
|
@@ -2649,12 +2669,12 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2649
2669
|
|
|
2650
2670
|
// src/tools/code/bash.ts
|
|
2651
2671
|
import { spawn as spawn2 } from "child_process";
|
|
2652
|
-
var DEFAULT_TIMEOUT_MS,
|
|
2672
|
+
var DEFAULT_TIMEOUT_MS, DEFAULT_MAX_LINES2, MAX_OUTPUT_BYTES, bashTool;
|
|
2653
2673
|
var init_bash = __esm({
|
|
2654
2674
|
"src/tools/code/bash.ts"() {
|
|
2655
2675
|
"use strict";
|
|
2656
2676
|
DEFAULT_TIMEOUT_MS = 12e4;
|
|
2657
|
-
|
|
2677
|
+
DEFAULT_MAX_LINES2 = 500;
|
|
2658
2678
|
MAX_OUTPUT_BYTES = 3e4;
|
|
2659
2679
|
bashTool = {
|
|
2660
2680
|
clearable: true,
|
|
@@ -2685,7 +2705,7 @@ var init_bash = __esm({
|
|
|
2685
2705
|
}
|
|
2686
2706
|
},
|
|
2687
2707
|
async execute(input, context) {
|
|
2688
|
-
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines ||
|
|
2708
|
+
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES2;
|
|
2689
2709
|
const timeoutMs = input.timeout ? input.timeout * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
2690
2710
|
return new Promise((resolve2) => {
|
|
2691
2711
|
const child = spawn2("sh", ["-c", input.command], {
|
|
@@ -2759,8 +2779,16 @@ var init_bash = __esm({
|
|
|
2759
2779
|
|
|
2760
2780
|
// src/tools/code/grep.ts
|
|
2761
2781
|
import { exec } from "child_process";
|
|
2762
|
-
function
|
|
2763
|
-
const
|
|
2782
|
+
function clampContext(v) {
|
|
2783
|
+
const n = Math.floor(Number(v));
|
|
2784
|
+
return Number.isFinite(n) ? Math.min(100, Math.max(0, n)) : 0;
|
|
2785
|
+
}
|
|
2786
|
+
function formatResults(stdout, max, mode) {
|
|
2787
|
+
const trimmed = stdout.trim();
|
|
2788
|
+
if (mode !== "content") {
|
|
2789
|
+
return trimmed;
|
|
2790
|
+
}
|
|
2791
|
+
const lines = trimmed.split("\n");
|
|
2764
2792
|
let result = lines.join("\n");
|
|
2765
2793
|
if (lines.length >= max) {
|
|
2766
2794
|
result += `
|
|
@@ -2778,7 +2806,7 @@ var init_grep = __esm({
|
|
|
2778
2806
|
clearable: true,
|
|
2779
2807
|
definition: {
|
|
2780
2808
|
name: "grep",
|
|
2781
|
-
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
2809
|
+
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. Set outputMode to 'count' for per-file match counts (like grep -c) or 'filesWithMatches' for just the file paths (like grep -l). Add context (like grep -C), or contextBefore/contextAfter (like grep -B/-A), to include surrounding lines. Set caseInsensitive (like grep -i) for a case-insensitive search. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
2782
2810
|
inputSchema: {
|
|
2783
2811
|
type: "object",
|
|
2784
2812
|
properties: {
|
|
@@ -2797,6 +2825,27 @@ var init_grep = __esm({
|
|
|
2797
2825
|
maxResults: {
|
|
2798
2826
|
type: "number",
|
|
2799
2827
|
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
2828
|
+
},
|
|
2829
|
+
outputMode: {
|
|
2830
|
+
type: "string",
|
|
2831
|
+
enum: ["content", "count", "filesWithMatches"],
|
|
2832
|
+
description: "What to return. 'content' (default): matching lines with line numbers. 'count': number of matches per file, like grep -c. 'filesWithMatches': just the paths of files that contain a match, like grep -l."
|
|
2833
|
+
},
|
|
2834
|
+
context: {
|
|
2835
|
+
type: "number",
|
|
2836
|
+
description: "Lines of context to show before AND after each match, like grep -C. Content mode only."
|
|
2837
|
+
},
|
|
2838
|
+
contextBefore: {
|
|
2839
|
+
type: "number",
|
|
2840
|
+
description: "Lines of context before each match, like grep -B. Content mode only; ignored if context is set."
|
|
2841
|
+
},
|
|
2842
|
+
contextAfter: {
|
|
2843
|
+
type: "number",
|
|
2844
|
+
description: "Lines of context after each match, like grep -A. Content mode only; ignored if context is set."
|
|
2845
|
+
},
|
|
2846
|
+
caseInsensitive: {
|
|
2847
|
+
type: "boolean",
|
|
2848
|
+
description: "Case-insensitive search, like grep -i."
|
|
2800
2849
|
}
|
|
2801
2850
|
},
|
|
2802
2851
|
required: ["pattern"]
|
|
@@ -2804,20 +2853,55 @@ var init_grep = __esm({
|
|
|
2804
2853
|
},
|
|
2805
2854
|
async execute(input) {
|
|
2806
2855
|
const searchPath = input.path || ".";
|
|
2807
|
-
const max =
|
|
2856
|
+
const max = Math.max(
|
|
2857
|
+
1,
|
|
2858
|
+
Math.floor(Number(input.maxResults) || DEFAULT_MAX)
|
|
2859
|
+
);
|
|
2808
2860
|
const globFlag = input.glob ? ` --glob '${input.glob}'` : "";
|
|
2809
2861
|
const escaped = input.pattern.replace(/'/g, "'\\''");
|
|
2810
|
-
const
|
|
2811
|
-
const
|
|
2862
|
+
const mode = input.outputMode === "count" || input.outputMode === "filesWithMatches" ? input.outputMode : "content";
|
|
2863
|
+
const ci = input.caseInsensitive ? " -i" : "";
|
|
2864
|
+
let ctx = "";
|
|
2865
|
+
if (mode === "content") {
|
|
2866
|
+
if (input.context != null) {
|
|
2867
|
+
const c = clampContext(input.context);
|
|
2868
|
+
if (c > 0) {
|
|
2869
|
+
ctx = ` -C ${c}`;
|
|
2870
|
+
}
|
|
2871
|
+
} else {
|
|
2872
|
+
const b = input.contextBefore != null ? clampContext(input.contextBefore) : 0;
|
|
2873
|
+
const a = input.contextAfter != null ? clampContext(input.contextAfter) : 0;
|
|
2874
|
+
if (b > 0) {
|
|
2875
|
+
ctx += ` -B ${b}`;
|
|
2876
|
+
}
|
|
2877
|
+
if (a > 0) {
|
|
2878
|
+
ctx += ` -A ${a}`;
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
let rgFlags;
|
|
2883
|
+
let grepFlags;
|
|
2884
|
+
if (mode === "count") {
|
|
2885
|
+
rgFlags = `--count${ci}`;
|
|
2886
|
+
grepFlags = `-rc${ci}`;
|
|
2887
|
+
} else if (mode === "filesWithMatches") {
|
|
2888
|
+
rgFlags = `-l${ci}`;
|
|
2889
|
+
grepFlags = `-rl${ci}`;
|
|
2890
|
+
} else {
|
|
2891
|
+
rgFlags = `-n --no-heading${ci}${ctx} --max-count=${max}`;
|
|
2892
|
+
grepFlags = `-rn${ci}${ctx} --max-count=${max}`;
|
|
2893
|
+
}
|
|
2894
|
+
const rgCmd = `rg ${rgFlags}${globFlag} '${escaped}' ${searchPath}`;
|
|
2895
|
+
const grepCmd = `grep ${grepFlags} '${escaped}' ${searchPath} --include='*.ts' --include='*.tsx' --include='*.js' --include='*.json' --include='*.md'`;
|
|
2812
2896
|
return new Promise((resolve2) => {
|
|
2813
2897
|
exec(rgCmd, { maxBuffer: 512 * 1024 }, (err, stdout) => {
|
|
2814
2898
|
if (stdout?.trim()) {
|
|
2815
|
-
resolve2(formatResults(stdout, max));
|
|
2899
|
+
resolve2(formatResults(stdout, max, mode));
|
|
2816
2900
|
return;
|
|
2817
2901
|
}
|
|
2818
2902
|
exec(grepCmd, { maxBuffer: 512 * 1024 }, (_err, grepStdout) => {
|
|
2819
2903
|
if (grepStdout?.trim()) {
|
|
2820
|
-
resolve2(formatResults(grepStdout, max));
|
|
2904
|
+
resolve2(formatResults(grepStdout, max, mode));
|
|
2821
2905
|
} else {
|
|
2822
2906
|
resolve2("No matches found.");
|
|
2823
2907
|
}
|
|
@@ -4666,86 +4750,15 @@ var COMMON_READ_TOOLS, COMMON_READ_TOOL_NAMES;
|
|
|
4666
4750
|
var init_tools2 = __esm({
|
|
4667
4751
|
"src/subagents/common/tools.ts"() {
|
|
4668
4752
|
"use strict";
|
|
4753
|
+
init_readFile();
|
|
4754
|
+
init_listDir();
|
|
4755
|
+
init_grep();
|
|
4756
|
+
init_glob();
|
|
4669
4757
|
COMMON_READ_TOOLS = [
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
type: "object",
|
|
4675
|
-
properties: {
|
|
4676
|
-
path: {
|
|
4677
|
-
type: "string",
|
|
4678
|
-
description: "The file path to read, relative to the project root."
|
|
4679
|
-
},
|
|
4680
|
-
offset: {
|
|
4681
|
-
type: "number",
|
|
4682
|
-
description: "Line number to start reading from (1-indexed). Use a negative number to read from the end (e.g., -50 reads the last 50 lines). Defaults to 1."
|
|
4683
|
-
},
|
|
4684
|
-
maxLines: {
|
|
4685
|
-
type: "number",
|
|
4686
|
-
description: "Maximum number of lines to return. Defaults to 500. Set to 0 for no limit."
|
|
4687
|
-
}
|
|
4688
|
-
},
|
|
4689
|
-
required: ["path"]
|
|
4690
|
-
}
|
|
4691
|
-
},
|
|
4692
|
-
{
|
|
4693
|
-
name: "listDir",
|
|
4694
|
-
description: "List the contents of a directory with one level of subdirectory expansion. Shows file sizes and collapses single-child directory chains (a/b/c/ shown as one entry). Use this for a quick overview of a directory's structure. For finding files across the whole project, use glob instead.",
|
|
4695
|
-
inputSchema: {
|
|
4696
|
-
type: "object",
|
|
4697
|
-
properties: {
|
|
4698
|
-
path: {
|
|
4699
|
-
type: "string",
|
|
4700
|
-
description: 'Directory path to list, relative to project root. Defaults to ".".'
|
|
4701
|
-
}
|
|
4702
|
-
}
|
|
4703
|
-
}
|
|
4704
|
-
},
|
|
4705
|
-
{
|
|
4706
|
-
name: "grep",
|
|
4707
|
-
description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
|
|
4708
|
-
inputSchema: {
|
|
4709
|
-
type: "object",
|
|
4710
|
-
properties: {
|
|
4711
|
-
pattern: {
|
|
4712
|
-
type: "string",
|
|
4713
|
-
description: "The search pattern (regex supported)."
|
|
4714
|
-
},
|
|
4715
|
-
path: {
|
|
4716
|
-
type: "string",
|
|
4717
|
-
description: "Directory or file to search in. Defaults to current directory."
|
|
4718
|
-
},
|
|
4719
|
-
glob: {
|
|
4720
|
-
type: "string",
|
|
4721
|
-
description: 'File glob to filter (e.g., "*.ts"). Only used with ripgrep.'
|
|
4722
|
-
},
|
|
4723
|
-
maxResults: {
|
|
4724
|
-
type: "number",
|
|
4725
|
-
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
4726
|
-
}
|
|
4727
|
-
},
|
|
4728
|
-
required: ["pattern"]
|
|
4729
|
-
}
|
|
4730
|
-
},
|
|
4731
|
-
{
|
|
4732
|
-
name: "glob",
|
|
4733
|
-
description: 'Find files matching a glob pattern. Returns matching file paths sorted alphabetically (default 200 results). Use this to discover project structure, find files by name or extension, or check if a file exists. Common patterns: "**/*.ts" (all TypeScript files), "src/**/*.tsx" (React components in src), "*.json" (root-level JSON files). Automatically excludes node_modules and .git.',
|
|
4734
|
-
inputSchema: {
|
|
4735
|
-
type: "object",
|
|
4736
|
-
properties: {
|
|
4737
|
-
pattern: {
|
|
4738
|
-
type: "string",
|
|
4739
|
-
description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json").'
|
|
4740
|
-
},
|
|
4741
|
-
maxResults: {
|
|
4742
|
-
type: "number",
|
|
4743
|
-
description: "Maximum number of file paths to return. Defaults to 200. Increase if you need the complete list."
|
|
4744
|
-
}
|
|
4745
|
-
},
|
|
4746
|
-
required: ["pattern"]
|
|
4747
|
-
}
|
|
4748
|
-
}
|
|
4758
|
+
readFileTool.definition,
|
|
4759
|
+
listDirTool.definition,
|
|
4760
|
+
grepTool.definition,
|
|
4761
|
+
globTool.definition
|
|
4749
4762
|
];
|
|
4750
4763
|
COMMON_READ_TOOL_NAMES = new Set(
|
|
4751
4764
|
COMMON_READ_TOOLS.map((t) => t.name)
|