@mindstudio-ai/remy 0.1.233 → 0.1.235
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 -105
- package/dist/index.js +119 -107
- 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
|
@@ -380,14 +380,14 @@ async function fetchRemyContext(config) {
|
|
|
380
380
|
// src/models/surfaces.ts
|
|
381
381
|
var MODEL_SURFACES = {
|
|
382
382
|
parent: {
|
|
383
|
-
default: "claude-
|
|
383
|
+
default: "claude-4-8-opus",
|
|
384
384
|
label: "Remy",
|
|
385
385
|
description: "The main Remy agent you chat with about your product. Writes code and manages delegation to other agents.",
|
|
386
386
|
modelType: "text",
|
|
387
387
|
userPickable: true
|
|
388
388
|
},
|
|
389
389
|
visualDesignExpert: {
|
|
390
|
-
default: "claude-
|
|
390
|
+
default: "claude-4-8-opus",
|
|
391
391
|
label: "Design Agent",
|
|
392
392
|
description: "Designs your product's interfaces, including components, layouts, typography, color, and visual identity.",
|
|
393
393
|
modelType: "text",
|
|
@@ -1895,7 +1895,7 @@ var compactConversationTool = {
|
|
|
1895
1895
|
|
|
1896
1896
|
// src/tools/code/readFile.ts
|
|
1897
1897
|
import fs12 from "fs/promises";
|
|
1898
|
-
var
|
|
1898
|
+
var DEFAULT_WINDOW = 500;
|
|
1899
1899
|
function isBinary(buffer) {
|
|
1900
1900
|
const sample = buffer.subarray(0, 8192);
|
|
1901
1901
|
for (let i = 0; i < sample.length; i++) {
|
|
@@ -1909,7 +1909,7 @@ var readFileTool = {
|
|
|
1909
1909
|
clearable: true,
|
|
1910
1910
|
definition: {
|
|
1911
1911
|
name: "readFile",
|
|
1912
|
-
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.",
|
|
1913
1913
|
inputSchema: {
|
|
1914
1914
|
type: "object",
|
|
1915
1915
|
properties: {
|
|
@@ -1917,13 +1917,17 @@ var readFileTool = {
|
|
|
1917
1917
|
type: "string",
|
|
1918
1918
|
description: "The file path to read, relative to the project root."
|
|
1919
1919
|
},
|
|
1920
|
-
|
|
1920
|
+
startLine: {
|
|
1921
1921
|
type: "number",
|
|
1922
|
-
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."
|
|
1923
1923
|
},
|
|
1924
|
-
|
|
1924
|
+
endLine: {
|
|
1925
1925
|
type: "number",
|
|
1926
|
-
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."
|
|
1927
1931
|
}
|
|
1928
1932
|
},
|
|
1929
1933
|
required: ["path"]
|
|
@@ -1940,22 +1944,37 @@ var readFileTool = {
|
|
|
1940
1944
|
const content = buffer.toString("utf-8");
|
|
1941
1945
|
const allLines = content.split("\n");
|
|
1942
1946
|
const totalLines = allLines.length;
|
|
1943
|
-
const
|
|
1947
|
+
const tail = input.tail != null ? Math.floor(Number(input.tail)) : void 0;
|
|
1944
1948
|
let startIdx;
|
|
1945
|
-
|
|
1946
|
-
|
|
1949
|
+
let endIdxExclusive;
|
|
1950
|
+
if (tail != null && tail > 0) {
|
|
1951
|
+
startIdx = Math.max(0, totalLines - tail);
|
|
1952
|
+
endIdxExclusive = totalLines;
|
|
1947
1953
|
} else {
|
|
1948
|
-
|
|
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
|
+
}
|
|
1949
1968
|
}
|
|
1950
|
-
const sliced = allLines.slice(startIdx,
|
|
1969
|
+
const sliced = allLines.slice(startIdx, endIdxExclusive);
|
|
1951
1970
|
const numbered = sliced.map((line, i) => `${String(startIdx + i + 1).padStart(4)} ${line}`).join("\n");
|
|
1952
1971
|
let result = numbered;
|
|
1953
|
-
const endLine = startIdx + sliced.length;
|
|
1954
1972
|
const displayStart = startIdx + 1;
|
|
1955
|
-
|
|
1973
|
+
const displayEnd = startIdx + sliced.length;
|
|
1974
|
+
if (displayStart > 1 || displayEnd < totalLines) {
|
|
1956
1975
|
result += `
|
|
1957
1976
|
|
|
1958
|
-
(showing lines ${displayStart}\u2013${
|
|
1977
|
+
(showing lines ${displayStart}\u2013${displayEnd} of ${totalLines} \u2014 pass startLine/endLine to read a different range)`;
|
|
1959
1978
|
}
|
|
1960
1979
|
return result;
|
|
1961
1980
|
} catch (err) {
|
|
@@ -2123,7 +2142,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2123
2142
|
// src/tools/code/bash.ts
|
|
2124
2143
|
import { spawn as spawn2 } from "child_process";
|
|
2125
2144
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
2126
|
-
var
|
|
2145
|
+
var DEFAULT_MAX_LINES2 = 500;
|
|
2127
2146
|
var MAX_OUTPUT_BYTES = 3e4;
|
|
2128
2147
|
var bashTool = {
|
|
2129
2148
|
clearable: true,
|
|
@@ -2154,7 +2173,7 @@ var bashTool = {
|
|
|
2154
2173
|
}
|
|
2155
2174
|
},
|
|
2156
2175
|
async execute(input, context) {
|
|
2157
|
-
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines ||
|
|
2176
|
+
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES2;
|
|
2158
2177
|
const timeoutMs = input.timeout ? input.timeout * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
2159
2178
|
return new Promise((resolve2) => {
|
|
2160
2179
|
const child = spawn2("sh", ["-c", input.command], {
|
|
@@ -2227,8 +2246,16 @@ var bashTool = {
|
|
|
2227
2246
|
// src/tools/code/grep.ts
|
|
2228
2247
|
import { exec } from "child_process";
|
|
2229
2248
|
var DEFAULT_MAX = 50;
|
|
2230
|
-
function
|
|
2231
|
-
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");
|
|
2232
2259
|
let result = lines.join("\n");
|
|
2233
2260
|
if (lines.length >= max) {
|
|
2234
2261
|
result += `
|
|
@@ -2241,7 +2268,7 @@ var grepTool = {
|
|
|
2241
2268
|
clearable: true,
|
|
2242
2269
|
definition: {
|
|
2243
2270
|
name: "grep",
|
|
2244
|
-
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.",
|
|
2245
2272
|
inputSchema: {
|
|
2246
2273
|
type: "object",
|
|
2247
2274
|
properties: {
|
|
@@ -2260,6 +2287,27 @@ var grepTool = {
|
|
|
2260
2287
|
maxResults: {
|
|
2261
2288
|
type: "number",
|
|
2262
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."
|
|
2263
2311
|
}
|
|
2264
2312
|
},
|
|
2265
2313
|
required: ["pattern"]
|
|
@@ -2267,20 +2315,55 @@ var grepTool = {
|
|
|
2267
2315
|
},
|
|
2268
2316
|
async execute(input) {
|
|
2269
2317
|
const searchPath = input.path || ".";
|
|
2270
|
-
const max =
|
|
2318
|
+
const max = Math.max(
|
|
2319
|
+
1,
|
|
2320
|
+
Math.floor(Number(input.maxResults) || DEFAULT_MAX)
|
|
2321
|
+
);
|
|
2271
2322
|
const globFlag = input.glob ? ` --glob '${input.glob}'` : "";
|
|
2272
2323
|
const escaped = input.pattern.replace(/'/g, "'\\''");
|
|
2273
|
-
const
|
|
2274
|
-
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'`;
|
|
2275
2358
|
return new Promise((resolve2) => {
|
|
2276
2359
|
exec(rgCmd, { maxBuffer: 512 * 1024 }, (err, stdout) => {
|
|
2277
2360
|
if (stdout?.trim()) {
|
|
2278
|
-
resolve2(formatResults(stdout, max));
|
|
2361
|
+
resolve2(formatResults(stdout, max, mode));
|
|
2279
2362
|
return;
|
|
2280
2363
|
}
|
|
2281
2364
|
exec(grepCmd, { maxBuffer: 512 * 1024 }, (_err, grepStdout) => {
|
|
2282
2365
|
if (grepStdout?.trim()) {
|
|
2283
|
-
resolve2(formatResults(grepStdout, max));
|
|
2366
|
+
resolve2(formatResults(grepStdout, max, mode));
|
|
2284
2367
|
} else {
|
|
2285
2368
|
resolve2("No matches found.");
|
|
2286
2369
|
}
|
|
@@ -3960,85 +4043,10 @@ var screenshotTool = {
|
|
|
3960
4043
|
|
|
3961
4044
|
// src/subagents/common/tools.ts
|
|
3962
4045
|
var COMMON_READ_TOOLS = [
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
type: "object",
|
|
3968
|
-
properties: {
|
|
3969
|
-
path: {
|
|
3970
|
-
type: "string",
|
|
3971
|
-
description: "The file path to read, relative to the project root."
|
|
3972
|
-
},
|
|
3973
|
-
offset: {
|
|
3974
|
-
type: "number",
|
|
3975
|
-
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."
|
|
3976
|
-
},
|
|
3977
|
-
maxLines: {
|
|
3978
|
-
type: "number",
|
|
3979
|
-
description: "Maximum number of lines to return. Defaults to 500. Set to 0 for no limit."
|
|
3980
|
-
}
|
|
3981
|
-
},
|
|
3982
|
-
required: ["path"]
|
|
3983
|
-
}
|
|
3984
|
-
},
|
|
3985
|
-
{
|
|
3986
|
-
name: "listDir",
|
|
3987
|
-
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.",
|
|
3988
|
-
inputSchema: {
|
|
3989
|
-
type: "object",
|
|
3990
|
-
properties: {
|
|
3991
|
-
path: {
|
|
3992
|
-
type: "string",
|
|
3993
|
-
description: 'Directory path to list, relative to project root. Defaults to ".".'
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3996
|
-
}
|
|
3997
|
-
},
|
|
3998
|
-
{
|
|
3999
|
-
name: "grep",
|
|
4000
|
-
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.",
|
|
4001
|
-
inputSchema: {
|
|
4002
|
-
type: "object",
|
|
4003
|
-
properties: {
|
|
4004
|
-
pattern: {
|
|
4005
|
-
type: "string",
|
|
4006
|
-
description: "The search pattern (regex supported)."
|
|
4007
|
-
},
|
|
4008
|
-
path: {
|
|
4009
|
-
type: "string",
|
|
4010
|
-
description: "Directory or file to search in. Defaults to current directory."
|
|
4011
|
-
},
|
|
4012
|
-
glob: {
|
|
4013
|
-
type: "string",
|
|
4014
|
-
description: 'File glob to filter (e.g., "*.ts"). Only used with ripgrep.'
|
|
4015
|
-
},
|
|
4016
|
-
maxResults: {
|
|
4017
|
-
type: "number",
|
|
4018
|
-
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
4019
|
-
}
|
|
4020
|
-
},
|
|
4021
|
-
required: ["pattern"]
|
|
4022
|
-
}
|
|
4023
|
-
},
|
|
4024
|
-
{
|
|
4025
|
-
name: "glob",
|
|
4026
|
-
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.',
|
|
4027
|
-
inputSchema: {
|
|
4028
|
-
type: "object",
|
|
4029
|
-
properties: {
|
|
4030
|
-
pattern: {
|
|
4031
|
-
type: "string",
|
|
4032
|
-
description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json").'
|
|
4033
|
-
},
|
|
4034
|
-
maxResults: {
|
|
4035
|
-
type: "number",
|
|
4036
|
-
description: "Maximum number of file paths to return. Defaults to 200. Increase if you need the complete list."
|
|
4037
|
-
}
|
|
4038
|
-
},
|
|
4039
|
-
required: ["pattern"]
|
|
4040
|
-
}
|
|
4041
|
-
}
|
|
4046
|
+
readFileTool.definition,
|
|
4047
|
+
listDirTool.definition,
|
|
4048
|
+
grepTool.definition,
|
|
4049
|
+
globTool.definition
|
|
4042
4050
|
];
|
|
4043
4051
|
var COMMON_READ_TOOL_NAMES = new Set(
|
|
4044
4052
|
COMMON_READ_TOOLS.map((t) => t.name)
|
package/dist/index.js
CHANGED
|
@@ -1996,14 +1996,14 @@ var init_surfaces = __esm({
|
|
|
1996
1996
|
"use strict";
|
|
1997
1997
|
MODEL_SURFACES = {
|
|
1998
1998
|
parent: {
|
|
1999
|
-
default: "claude-
|
|
1999
|
+
default: "claude-4-8-opus",
|
|
2000
2000
|
label: "Remy",
|
|
2001
2001
|
description: "The main Remy agent you chat with about your product. Writes code and manages delegation to other agents.",
|
|
2002
2002
|
modelType: "text",
|
|
2003
2003
|
userPickable: true
|
|
2004
2004
|
},
|
|
2005
2005
|
visualDesignExpert: {
|
|
2006
|
-
default: "claude-
|
|
2006
|
+
default: "claude-4-8-opus",
|
|
2007
2007
|
label: "Design Agent",
|
|
2008
2008
|
description: "Designs your product's interfaces, including components, layouts, typography, color, and visual identity.",
|
|
2009
2009
|
modelType: "text",
|
|
@@ -2409,16 +2409,16 @@ function isBinary(buffer) {
|
|
|
2409
2409
|
}
|
|
2410
2410
|
return false;
|
|
2411
2411
|
}
|
|
2412
|
-
var
|
|
2412
|
+
var DEFAULT_WINDOW, readFileTool;
|
|
2413
2413
|
var init_readFile = __esm({
|
|
2414
2414
|
"src/tools/code/readFile.ts"() {
|
|
2415
2415
|
"use strict";
|
|
2416
|
-
|
|
2416
|
+
DEFAULT_WINDOW = 500;
|
|
2417
2417
|
readFileTool = {
|
|
2418
2418
|
clearable: true,
|
|
2419
2419
|
definition: {
|
|
2420
2420
|
name: "readFile",
|
|
2421
|
-
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.",
|
|
2422
2422
|
inputSchema: {
|
|
2423
2423
|
type: "object",
|
|
2424
2424
|
properties: {
|
|
@@ -2426,13 +2426,17 @@ var init_readFile = __esm({
|
|
|
2426
2426
|
type: "string",
|
|
2427
2427
|
description: "The file path to read, relative to the project root."
|
|
2428
2428
|
},
|
|
2429
|
-
|
|
2429
|
+
startLine: {
|
|
2430
2430
|
type: "number",
|
|
2431
|
-
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."
|
|
2432
2432
|
},
|
|
2433
|
-
|
|
2433
|
+
endLine: {
|
|
2434
2434
|
type: "number",
|
|
2435
|
-
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."
|
|
2436
2440
|
}
|
|
2437
2441
|
},
|
|
2438
2442
|
required: ["path"]
|
|
@@ -2449,22 +2453,37 @@ var init_readFile = __esm({
|
|
|
2449
2453
|
const content = buffer.toString("utf-8");
|
|
2450
2454
|
const allLines = content.split("\n");
|
|
2451
2455
|
const totalLines = allLines.length;
|
|
2452
|
-
const
|
|
2456
|
+
const tail = input.tail != null ? Math.floor(Number(input.tail)) : void 0;
|
|
2453
2457
|
let startIdx;
|
|
2454
|
-
|
|
2455
|
-
|
|
2458
|
+
let endIdxExclusive;
|
|
2459
|
+
if (tail != null && tail > 0) {
|
|
2460
|
+
startIdx = Math.max(0, totalLines - tail);
|
|
2461
|
+
endIdxExclusive = totalLines;
|
|
2456
2462
|
} else {
|
|
2457
|
-
|
|
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
|
+
}
|
|
2458
2477
|
}
|
|
2459
|
-
const sliced = allLines.slice(startIdx,
|
|
2478
|
+
const sliced = allLines.slice(startIdx, endIdxExclusive);
|
|
2460
2479
|
const numbered = sliced.map((line, i) => `${String(startIdx + i + 1).padStart(4)} ${line}`).join("\n");
|
|
2461
2480
|
let result = numbered;
|
|
2462
|
-
const endLine = startIdx + sliced.length;
|
|
2463
2481
|
const displayStart = startIdx + 1;
|
|
2464
|
-
|
|
2482
|
+
const displayEnd = startIdx + sliced.length;
|
|
2483
|
+
if (displayStart > 1 || displayEnd < totalLines) {
|
|
2465
2484
|
result += `
|
|
2466
2485
|
|
|
2467
|
-
(showing lines ${displayStart}\u2013${
|
|
2486
|
+
(showing lines ${displayStart}\u2013${displayEnd} of ${totalLines} \u2014 pass startLine/endLine to read a different range)`;
|
|
2468
2487
|
}
|
|
2469
2488
|
return result;
|
|
2470
2489
|
} catch (err) {
|
|
@@ -2650,12 +2669,12 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2650
2669
|
|
|
2651
2670
|
// src/tools/code/bash.ts
|
|
2652
2671
|
import { spawn as spawn2 } from "child_process";
|
|
2653
|
-
var DEFAULT_TIMEOUT_MS,
|
|
2672
|
+
var DEFAULT_TIMEOUT_MS, DEFAULT_MAX_LINES2, MAX_OUTPUT_BYTES, bashTool;
|
|
2654
2673
|
var init_bash = __esm({
|
|
2655
2674
|
"src/tools/code/bash.ts"() {
|
|
2656
2675
|
"use strict";
|
|
2657
2676
|
DEFAULT_TIMEOUT_MS = 12e4;
|
|
2658
|
-
|
|
2677
|
+
DEFAULT_MAX_LINES2 = 500;
|
|
2659
2678
|
MAX_OUTPUT_BYTES = 3e4;
|
|
2660
2679
|
bashTool = {
|
|
2661
2680
|
clearable: true,
|
|
@@ -2686,7 +2705,7 @@ var init_bash = __esm({
|
|
|
2686
2705
|
}
|
|
2687
2706
|
},
|
|
2688
2707
|
async execute(input, context) {
|
|
2689
|
-
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines ||
|
|
2708
|
+
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES2;
|
|
2690
2709
|
const timeoutMs = input.timeout ? input.timeout * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
2691
2710
|
return new Promise((resolve2) => {
|
|
2692
2711
|
const child = spawn2("sh", ["-c", input.command], {
|
|
@@ -2760,8 +2779,16 @@ var init_bash = __esm({
|
|
|
2760
2779
|
|
|
2761
2780
|
// src/tools/code/grep.ts
|
|
2762
2781
|
import { exec } from "child_process";
|
|
2763
|
-
function
|
|
2764
|
-
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");
|
|
2765
2792
|
let result = lines.join("\n");
|
|
2766
2793
|
if (lines.length >= max) {
|
|
2767
2794
|
result += `
|
|
@@ -2779,7 +2806,7 @@ var init_grep = __esm({
|
|
|
2779
2806
|
clearable: true,
|
|
2780
2807
|
definition: {
|
|
2781
2808
|
name: "grep",
|
|
2782
|
-
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.",
|
|
2783
2810
|
inputSchema: {
|
|
2784
2811
|
type: "object",
|
|
2785
2812
|
properties: {
|
|
@@ -2798,6 +2825,27 @@ var init_grep = __esm({
|
|
|
2798
2825
|
maxResults: {
|
|
2799
2826
|
type: "number",
|
|
2800
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."
|
|
2801
2849
|
}
|
|
2802
2850
|
},
|
|
2803
2851
|
required: ["pattern"]
|
|
@@ -2805,20 +2853,55 @@ var init_grep = __esm({
|
|
|
2805
2853
|
},
|
|
2806
2854
|
async execute(input) {
|
|
2807
2855
|
const searchPath = input.path || ".";
|
|
2808
|
-
const max =
|
|
2856
|
+
const max = Math.max(
|
|
2857
|
+
1,
|
|
2858
|
+
Math.floor(Number(input.maxResults) || DEFAULT_MAX)
|
|
2859
|
+
);
|
|
2809
2860
|
const globFlag = input.glob ? ` --glob '${input.glob}'` : "";
|
|
2810
2861
|
const escaped = input.pattern.replace(/'/g, "'\\''");
|
|
2811
|
-
const
|
|
2812
|
-
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'`;
|
|
2813
2896
|
return new Promise((resolve2) => {
|
|
2814
2897
|
exec(rgCmd, { maxBuffer: 512 * 1024 }, (err, stdout) => {
|
|
2815
2898
|
if (stdout?.trim()) {
|
|
2816
|
-
resolve2(formatResults(stdout, max));
|
|
2899
|
+
resolve2(formatResults(stdout, max, mode));
|
|
2817
2900
|
return;
|
|
2818
2901
|
}
|
|
2819
2902
|
exec(grepCmd, { maxBuffer: 512 * 1024 }, (_err, grepStdout) => {
|
|
2820
2903
|
if (grepStdout?.trim()) {
|
|
2821
|
-
resolve2(formatResults(grepStdout, max));
|
|
2904
|
+
resolve2(formatResults(grepStdout, max, mode));
|
|
2822
2905
|
} else {
|
|
2823
2906
|
resolve2("No matches found.");
|
|
2824
2907
|
}
|
|
@@ -4667,86 +4750,15 @@ var COMMON_READ_TOOLS, COMMON_READ_TOOL_NAMES;
|
|
|
4667
4750
|
var init_tools2 = __esm({
|
|
4668
4751
|
"src/subagents/common/tools.ts"() {
|
|
4669
4752
|
"use strict";
|
|
4753
|
+
init_readFile();
|
|
4754
|
+
init_listDir();
|
|
4755
|
+
init_grep();
|
|
4756
|
+
init_glob();
|
|
4670
4757
|
COMMON_READ_TOOLS = [
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
type: "object",
|
|
4676
|
-
properties: {
|
|
4677
|
-
path: {
|
|
4678
|
-
type: "string",
|
|
4679
|
-
description: "The file path to read, relative to the project root."
|
|
4680
|
-
},
|
|
4681
|
-
offset: {
|
|
4682
|
-
type: "number",
|
|
4683
|
-
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."
|
|
4684
|
-
},
|
|
4685
|
-
maxLines: {
|
|
4686
|
-
type: "number",
|
|
4687
|
-
description: "Maximum number of lines to return. Defaults to 500. Set to 0 for no limit."
|
|
4688
|
-
}
|
|
4689
|
-
},
|
|
4690
|
-
required: ["path"]
|
|
4691
|
-
}
|
|
4692
|
-
},
|
|
4693
|
-
{
|
|
4694
|
-
name: "listDir",
|
|
4695
|
-
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.",
|
|
4696
|
-
inputSchema: {
|
|
4697
|
-
type: "object",
|
|
4698
|
-
properties: {
|
|
4699
|
-
path: {
|
|
4700
|
-
type: "string",
|
|
4701
|
-
description: 'Directory path to list, relative to project root. Defaults to ".".'
|
|
4702
|
-
}
|
|
4703
|
-
}
|
|
4704
|
-
}
|
|
4705
|
-
},
|
|
4706
|
-
{
|
|
4707
|
-
name: "grep",
|
|
4708
|
-
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.",
|
|
4709
|
-
inputSchema: {
|
|
4710
|
-
type: "object",
|
|
4711
|
-
properties: {
|
|
4712
|
-
pattern: {
|
|
4713
|
-
type: "string",
|
|
4714
|
-
description: "The search pattern (regex supported)."
|
|
4715
|
-
},
|
|
4716
|
-
path: {
|
|
4717
|
-
type: "string",
|
|
4718
|
-
description: "Directory or file to search in. Defaults to current directory."
|
|
4719
|
-
},
|
|
4720
|
-
glob: {
|
|
4721
|
-
type: "string",
|
|
4722
|
-
description: 'File glob to filter (e.g., "*.ts"). Only used with ripgrep.'
|
|
4723
|
-
},
|
|
4724
|
-
maxResults: {
|
|
4725
|
-
type: "number",
|
|
4726
|
-
description: "Maximum number of matching lines to return. Defaults to 50. Increase if you need more comprehensive results."
|
|
4727
|
-
}
|
|
4728
|
-
},
|
|
4729
|
-
required: ["pattern"]
|
|
4730
|
-
}
|
|
4731
|
-
},
|
|
4732
|
-
{
|
|
4733
|
-
name: "glob",
|
|
4734
|
-
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.',
|
|
4735
|
-
inputSchema: {
|
|
4736
|
-
type: "object",
|
|
4737
|
-
properties: {
|
|
4738
|
-
pattern: {
|
|
4739
|
-
type: "string",
|
|
4740
|
-
description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.tsx", "*.json").'
|
|
4741
|
-
},
|
|
4742
|
-
maxResults: {
|
|
4743
|
-
type: "number",
|
|
4744
|
-
description: "Maximum number of file paths to return. Defaults to 200. Increase if you need the complete list."
|
|
4745
|
-
}
|
|
4746
|
-
},
|
|
4747
|
-
required: ["pattern"]
|
|
4748
|
-
}
|
|
4749
|
-
}
|
|
4758
|
+
readFileTool.definition,
|
|
4759
|
+
listDirTool.definition,
|
|
4760
|
+
grepTool.definition,
|
|
4761
|
+
globTool.definition
|
|
4750
4762
|
];
|
|
4751
4763
|
COMMON_READ_TOOL_NAMES = new Set(
|
|
4752
4764
|
COMMON_READ_TOOLS.map((t) => t.name)
|