flavor-code 1.3.8 → 1.3.10
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/{app-OLOUQDIG.js → app-YSBW7GXH.js} +1 -1
- package/dist/{chunk-EJCI3VB5.js → chunk-T2ARW6CZ.js} +1 -1
- package/dist/{chunk-GAQJZBOF.js → chunk-Y3DPUAEJ.js} +50 -24
- package/dist/cli.js +3 -3
- package/dist/desktop/main.js +50 -24
- package/dist/sdk/index.js +2 -2
- package/dist/tools/search.d.ts +2 -0
- package/package.json +1 -1
|
@@ -56,6 +56,8 @@ function normalizeProviderError(error) {
|
|
|
56
56
|
code = "context_overflow";
|
|
57
57
|
} else if (status === 404 || /model.*not.?found|not.?found.*model/.test(searchable)) {
|
|
58
58
|
code = "model_not_found";
|
|
59
|
+
} else if (status !== void 0 && status >= 500 && status <= 599) {
|
|
60
|
+
code = "network";
|
|
59
61
|
} else if (status === void 0 && /econn|enet|socket|network|fetch failed|connection|timeout/.test(searchable)) {
|
|
60
62
|
code = "network";
|
|
61
63
|
}
|
|
@@ -1981,9 +1983,17 @@ var FILE_TYPE_EXTENSIONS = {
|
|
|
1981
1983
|
python: [".py", ".pyi"],
|
|
1982
1984
|
typescript: [".ts", ".tsx", ".mts", ".cts"]
|
|
1983
1985
|
};
|
|
1986
|
+
var BooleanInput = z.preprocess((value) => {
|
|
1987
|
+
if (typeof value !== "string") return value;
|
|
1988
|
+
const normalized = value.trim().toLowerCase();
|
|
1989
|
+
if (normalized === "true") return true;
|
|
1990
|
+
if (normalized === "false") return false;
|
|
1991
|
+
return value;
|
|
1992
|
+
}, z.boolean());
|
|
1984
1993
|
var GlobInput = z.object({
|
|
1985
1994
|
pattern: z.string().min(1),
|
|
1986
1995
|
path: z.string().min(1).describe('Workspace-relative search directory. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
1996
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
1987
1997
|
limit: z.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
1988
1998
|
});
|
|
1989
1999
|
var GrepInput = z.object({
|
|
@@ -1991,6 +2001,7 @@ var GrepInput = z.object({
|
|
|
1991
2001
|
path: z.string().min(1).describe('Workspace-relative search path. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
1992
2002
|
glob: z.string().min(1).nullable().optional(),
|
|
1993
2003
|
fileType: z.enum(FILE_TYPES).nullable().optional(),
|
|
2004
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
1994
2005
|
context: z.coerce.number().int().nonnegative().max(100).nullable().optional(),
|
|
1995
2006
|
limit: z.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
1996
2007
|
});
|
|
@@ -2004,23 +2015,26 @@ function createGlobTool(workspace, options = {}) {
|
|
|
2004
2015
|
paths: (input) => [scope(root, searchPath(input.path))],
|
|
2005
2016
|
summarize: (input) => {
|
|
2006
2017
|
const path = searchPath(input.path);
|
|
2007
|
-
|
|
2018
|
+
const ignored2 = input.includeIgnored === true ? " (including ignored files)" : "";
|
|
2019
|
+
return (path ? `pattern: "${input.pattern}" in ${path}` : `pattern: "${input.pattern}"`) + ignored2;
|
|
2008
2020
|
},
|
|
2009
2021
|
execute: async (input, signal) => {
|
|
2010
2022
|
const limit = input.limit ?? options.defaultLimit ?? DEFAULT_RESULT_LIMIT;
|
|
2011
2023
|
const start = scope(root, searchPath(input.path));
|
|
2024
|
+
if (isGitMetadataPath(root, start)) return { matches: [], truncated: false };
|
|
2012
2025
|
const matcher = globRegex(input.pattern);
|
|
2013
2026
|
const ignoreBudget = createIgnoreBudget(resources);
|
|
2027
|
+
const includeIgnored = input.includeIgnored === true;
|
|
2014
2028
|
let paths;
|
|
2015
2029
|
if (options.forceNode === true) {
|
|
2016
|
-
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, ignoreBudget);
|
|
2030
|
+
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, ignoreBudget, includeIgnored);
|
|
2017
2031
|
} else {
|
|
2018
2032
|
try {
|
|
2019
|
-
paths = await rgFiles(root, start, input.pattern, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
2033
|
+
paths = await rgFiles(root, start, input.pattern, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget, includeIgnored);
|
|
2020
2034
|
} catch (error) {
|
|
2021
2035
|
if (signal.aborted) throw signal.reason;
|
|
2022
2036
|
if (!(error instanceof SearchSpawnError) || !error.fallbackSafe) throw error;
|
|
2023
|
-
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, createIgnoreBudget(resources));
|
|
2037
|
+
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, createIgnoreBudget(resources), includeIgnored);
|
|
2024
2038
|
}
|
|
2025
2039
|
}
|
|
2026
2040
|
const matches = paths.filter((path) => matcher.test(path)).sort(comparePaths);
|
|
@@ -2040,24 +2054,27 @@ function createGrepTool(workspace, options = {}) {
|
|
|
2040
2054
|
const path = searchPath(input.path);
|
|
2041
2055
|
const where = path ? ` in ${path}` : "";
|
|
2042
2056
|
const kind = input.fileType ? ` [${input.fileType}]` : "";
|
|
2043
|
-
|
|
2057
|
+
const ignored2 = input.includeIgnored === true ? " (including ignored files)" : "";
|
|
2058
|
+
return `pattern: /${input.pattern}/${kind}${where}${ignored2}`;
|
|
2044
2059
|
},
|
|
2045
2060
|
execute: async (input, signal) => {
|
|
2046
2061
|
const expression = new RegExp(input.pattern);
|
|
2047
2062
|
const limit = input.limit ?? options.defaultLimit ?? DEFAULT_RESULT_LIMIT;
|
|
2048
2063
|
const context = input.context ?? 0;
|
|
2049
2064
|
const start = await resolveGrepPath(root, searchPath(input.path));
|
|
2065
|
+
if (isGitMetadataPath(root, start)) return { matches: [], truncated: false };
|
|
2050
2066
|
const ignoreBudget = createIgnoreBudget(resources);
|
|
2067
|
+
const includeIgnored = input.includeIgnored === true;
|
|
2051
2068
|
let matches;
|
|
2052
2069
|
if (options.forceNode === true) {
|
|
2053
|
-
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
2070
|
+
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget, includeIgnored);
|
|
2054
2071
|
} else {
|
|
2055
2072
|
try {
|
|
2056
2073
|
matches = await rgGrep(root, start, input, context, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
2057
2074
|
} catch (error) {
|
|
2058
2075
|
if (signal.aborted) throw signal.reason;
|
|
2059
2076
|
if (!(error instanceof SearchSpawnError) || !error.fallbackSafe) throw error;
|
|
2060
|
-
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, createIgnoreBudget(resources));
|
|
2077
|
+
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, createIgnoreBudget(resources), includeIgnored);
|
|
2061
2078
|
}
|
|
2062
2079
|
}
|
|
2063
2080
|
matches.sort(compareGrepMatches);
|
|
@@ -2065,10 +2082,10 @@ function createGrepTool(workspace, options = {}) {
|
|
|
2065
2082
|
}
|
|
2066
2083
|
};
|
|
2067
2084
|
}
|
|
2068
|
-
async function rgFiles(root, start, pattern, signal, executable, argsPrefix, limit, maxBytes, resources, ignoreBudget) {
|
|
2085
|
+
async function rgFiles(root, start, pattern, signal, executable, argsPrefix, limit, maxBytes, resources, ignoreBudget, includeIgnored) {
|
|
2069
2086
|
const target = relative4(root, start) || ".";
|
|
2070
2087
|
const matcher = globRegex(pattern);
|
|
2071
|
-
const ignoreLayers = await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
2088
|
+
const ignoreLayers = includeIgnored ? [] : await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
2072
2089
|
const paths = [];
|
|
2073
2090
|
const parser = delimitedParser(0, (record) => {
|
|
2074
2091
|
if (record.length === 0) return true;
|
|
@@ -2077,7 +2094,10 @@ async function rgFiles(root, start, pattern, signal, executable, argsPrefix, lim
|
|
|
2077
2094
|
retainTopK(paths, path, limit, comparePaths);
|
|
2078
2095
|
return true;
|
|
2079
2096
|
});
|
|
2080
|
-
const
|
|
2097
|
+
const args = [...argsPrefix, "--files", "--null", "--sort", "path", "--hidden", "--glob", "!.git", "--glob", "!.git/**"];
|
|
2098
|
+
if (includeIgnored) args.push("--no-ignore");
|
|
2099
|
+
args.push("--glob", pattern, "--", target);
|
|
2100
|
+
const output = await runStreaming(executable, args, root, signal, maxBytes, parser);
|
|
2081
2101
|
if (!output.stoppedEarly && output.code !== 0 && output.code !== 1) throw new Error(output.stderr || `ripgrep exited with ${output.code}`);
|
|
2082
2102
|
parser.finish();
|
|
2083
2103
|
return paths;
|
|
@@ -2087,12 +2107,13 @@ async function rgGrep(root, start, input, context, signal, executable, argsPrefi
|
|
|
2087
2107
|
if (input.fileType !== void 0 && input.fileType !== null && typeExtensions === void 0) {
|
|
2088
2108
|
throw new Error(`Unsupported file type: ${input.fileType}`);
|
|
2089
2109
|
}
|
|
2090
|
-
const args = ["--json", "--line-number", "--column", "--sort", "path", "--hidden", "--glob", "!.git", "--max-filesize", String(maxFileBytes), "--context", String(context)];
|
|
2110
|
+
const args = ["--json", "--line-number", "--column", "--sort", "path", "--hidden", "--glob", "!.git", "--glob", "!.git/**", "--max-filesize", String(maxFileBytes), "--context", String(context)];
|
|
2111
|
+
if (input.includeIgnored === true) args.push("--no-ignore");
|
|
2091
2112
|
if (input.glob !== void 0 && input.glob !== null) args.push("--glob", input.glob);
|
|
2092
2113
|
else for (const extension of typeExtensions ?? []) args.push("--glob", `*${extension}`);
|
|
2093
2114
|
args.push("--regexp", input.pattern, "--", relative4(root, start) || ".");
|
|
2094
2115
|
const matches = [];
|
|
2095
|
-
const ignoreLayers = await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
2116
|
+
const ignoreLayers = input.includeIgnored === true ? [] : await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
2096
2117
|
const parser = delimitedParser(10, (record) => {
|
|
2097
2118
|
if (record.length === 0) return true;
|
|
2098
2119
|
const event = JSON.parse(decodeUtf8(record, "ripgrep JSON"));
|
|
@@ -2147,8 +2168,8 @@ async function hydrateContext(root, matches, context, signal, maxFileBytes, maxT
|
|
|
2147
2168
|
}
|
|
2148
2169
|
}
|
|
2149
2170
|
}
|
|
2150
|
-
async function nodeGrep(root, start, glob, type, expression, context, signal, maxMatches, maxFileBytes, maxSearchBytes, resources, ignoreBudget) {
|
|
2151
|
-
const files = await nodeFiles(root, start, signal, () => true, resources.maxDiscoveredFiles + 1, resources, ignoreBudget);
|
|
2171
|
+
async function nodeGrep(root, start, glob, type, expression, context, signal, maxMatches, maxFileBytes, maxSearchBytes, resources, ignoreBudget, includeIgnored) {
|
|
2172
|
+
const files = await nodeFiles(root, start, signal, () => true, resources.maxDiscoveredFiles + 1, resources, ignoreBudget, includeIgnored);
|
|
2152
2173
|
if (files.length > resources.maxDiscoveredFiles) throw new Error(`Aggregate discovered file limit of ${resources.maxDiscoveredFiles} exceeded`);
|
|
2153
2174
|
const matcher = glob === void 0 ? void 0 : globRegex(glob);
|
|
2154
2175
|
const extension = type === void 0 ? void 0 : typeExtension(type);
|
|
@@ -2190,23 +2211,25 @@ async function nodeGrep(root, start, glob, type, expression, context, signal, ma
|
|
|
2190
2211
|
}
|
|
2191
2212
|
return matches;
|
|
2192
2213
|
}
|
|
2193
|
-
async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBudget) {
|
|
2214
|
+
async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBudget, includeIgnored) {
|
|
2194
2215
|
const ignores = [];
|
|
2195
2216
|
const output = [];
|
|
2196
2217
|
const delta = relative4(root, start);
|
|
2197
2218
|
const segments = delta === "" ? [] : delta.split(sep4);
|
|
2198
2219
|
let ancestor = root;
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2220
|
+
if (!includeIgnored) {
|
|
2221
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
2222
|
+
noteIgnoreDirectory(ignoreBudget);
|
|
2223
|
+
await loadIgnoreFiles(ancestor, normalizedRelative(root, ancestor), ignores, ignoreBudget, signal);
|
|
2224
|
+
ancestor = resolve4(ancestor, segments[index]);
|
|
2225
|
+
}
|
|
2203
2226
|
}
|
|
2204
2227
|
async function walk(directory) {
|
|
2205
2228
|
abort(signal);
|
|
2206
2229
|
const relativeDirectory = normalizedRelative(root, directory);
|
|
2207
2230
|
const ruleCount = ignores.length;
|
|
2208
2231
|
noteIgnoreDirectory(ignoreBudget);
|
|
2209
|
-
await loadIgnoreFiles(directory, relativeDirectory, ignores, ignoreBudget, signal);
|
|
2232
|
+
if (!includeIgnored) await loadIgnoreFiles(directory, relativeDirectory, ignores, ignoreBudget, signal);
|
|
2210
2233
|
const handle = await opendir(directory);
|
|
2211
2234
|
const entries = [];
|
|
2212
2235
|
for await (const entry2 of handle) {
|
|
@@ -2219,7 +2242,7 @@ async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBu
|
|
|
2219
2242
|
abort(signal);
|
|
2220
2243
|
const absolute = resolve4(directory, entry2.name);
|
|
2221
2244
|
const path = normalizedRelative(root, absolute);
|
|
2222
|
-
if (entry2.name === ".git" || ignored(path, entry2.isDirectory(), ignores)) continue;
|
|
2245
|
+
if (entry2.name === ".git" || !includeIgnored && ignored(path, entry2.isDirectory(), ignores)) continue;
|
|
2223
2246
|
if (entry2.isDirectory()) await walk(absolute);
|
|
2224
2247
|
else if (entry2.isFile() && accept(path)) output.push(path);
|
|
2225
2248
|
if (output.length >= limit) break;
|
|
@@ -2388,6 +2411,9 @@ function normalizedRelative(root, path) {
|
|
|
2388
2411
|
function normalizePath(path) {
|
|
2389
2412
|
return path.replaceAll("\\", "/");
|
|
2390
2413
|
}
|
|
2414
|
+
function isGitMetadataPath(root, path) {
|
|
2415
|
+
return normalizedRelative(root, path).split("/").some((segment) => segment.toLowerCase() === ".git");
|
|
2416
|
+
}
|
|
2391
2417
|
function comparePaths(a, b) {
|
|
2392
2418
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
2393
2419
|
}
|
|
@@ -13965,8 +13991,8 @@ function toolsSection(toolNames) {
|
|
|
13965
13991
|
addToolRule(rules, toolNames, "Write", "Use `Write` to create a file only when a new file is necessary.");
|
|
13966
13992
|
addToolRule(rules, toolNames, "Edit", "Use `Edit` for precise replacements in existing files. Before editing, read the file and copy `oldText` verbatim from its actual current content \u2014 exact characters matter, including quote style (full-width vs ASCII) and version strings. Include enough surrounding lines to make the match unique.");
|
|
13967
13993
|
addToolRule(rules, toolNames, "ApplyPatch", "Use `ApplyPatch` only when an edit genuinely spans multiple regions of one file; hunks may relocate only when their exact context has one unique nearby match. Prefer `Edit` for a single small replacement \u2014 it is easier to get right.");
|
|
13968
|
-
addToolRule(rules, toolNames, "Glob", "Use `Glob` to find files by path pattern instead of shell directory crawling. Confirm the exact path before reading, searching, or editing; the search scope is limited to the workspace, so never pass absolute paths outside it.");
|
|
13969
|
-
addToolRule(rules, toolNames, "Grep", "Use `Grep` to search file contents instead of shell text-search commands.");
|
|
13994
|
+
addToolRule(rules, toolNames, "Glob", "Use `Glob` to find files by path pattern instead of shell directory crawling. Confirm the exact path before reading, searching, or editing; the search scope is limited to the workspace, so never pass absolute paths outside it. Set `includeIgnored: true` only when the user explicitly asks to inspect ignored files or an ignored path is required for the task.");
|
|
13995
|
+
addToolRule(rules, toolNames, "Grep", "Use `Grep` to search file contents instead of shell text-search commands. Set `includeIgnored: true` only when the user explicitly asks to inspect ignored files or an ignored path is required for the task.");
|
|
13970
13996
|
addToolRule(rules, toolNames, "Shell", "Use `Shell` for builds, tests, Git inspection, and commands without a dedicated tool. Keep commands scoped, non-interactive, and easy to audit.");
|
|
13971
13997
|
addToolRule(rules, toolNames, "LspFindRefs", "Use `LspFindRefs` to find all references to a symbol using the Language Server Protocol. Prefer this over Grep when you need precise semantic results.");
|
|
13972
13998
|
addToolRule(rules, toolNames, "LspHover", "Use `LspHover` to get type information and documentation for a symbol at a cursor position.");
|
|
@@ -22556,7 +22582,7 @@ ${expandSkillArguments(await skills.loadBody(skill), prompt)}`);
|
|
|
22556
22582
|
...additionalContext === void 0 ? {} : { additionalContext },
|
|
22557
22583
|
...getSteeringMessages === void 0 ? {} : { getSteeringMessages }
|
|
22558
22584
|
})) {
|
|
22559
|
-
if (event.type === "error" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
22585
|
+
if (event.type === "error" && event.error.code !== "network" && event.error.code !== "rate_limit" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
22560
22586
|
yield { ...event, error: {
|
|
22561
22587
|
...event.error,
|
|
22562
22588
|
message: `${event.error.message}. Configure providers and agents in .flavor/flavor.json or set OPENAI_API_KEY/ANTHROPIC_API_KEY.`
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
|
|
|
3
3
|
import {
|
|
4
4
|
FlavorRpcServer,
|
|
5
5
|
TraceRecorder
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-T2ARW6CZ.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
9
|
} from "./chunk-KKIBYDJI.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
packageVersion,
|
|
24
24
|
redactErrorText,
|
|
25
25
|
runPalBroker
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-Y3DPUAEJ.js";
|
|
27
27
|
import {
|
|
28
28
|
McpServerConfigSchema,
|
|
29
29
|
McpServerNameSchema,
|
|
@@ -877,7 +877,7 @@ async function runInteractiveCli(props) {
|
|
|
877
877
|
const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
|
|
878
878
|
import("./claude-ink-ORUA7GWG.js"),
|
|
879
879
|
import("react"),
|
|
880
|
-
import("./app-
|
|
880
|
+
import("./app-YSBW7GXH.js")
|
|
881
881
|
]);
|
|
882
882
|
const instance = await render(createElement(
|
|
883
883
|
AlternateScreen,
|
package/dist/desktop/main.js
CHANGED
|
@@ -4256,6 +4256,8 @@ function normalizeProviderError(error) {
|
|
|
4256
4256
|
code = "context_overflow";
|
|
4257
4257
|
} else if (status === 404 || /model.*not.?found|not.?found.*model/.test(searchable)) {
|
|
4258
4258
|
code = "model_not_found";
|
|
4259
|
+
} else if (status !== void 0 && status >= 500 && status <= 599) {
|
|
4260
|
+
code = "network";
|
|
4259
4261
|
} else if (status === void 0 && /econn|enet|socket|network|fetch failed|connection|timeout/.test(searchable)) {
|
|
4260
4262
|
code = "network";
|
|
4261
4263
|
}
|
|
@@ -14603,8 +14605,8 @@ function toolsSection(toolNames) {
|
|
|
14603
14605
|
addToolRule(rules, toolNames, "Write", "Use `Write` to create a file only when a new file is necessary.");
|
|
14604
14606
|
addToolRule(rules, toolNames, "Edit", "Use `Edit` for precise replacements in existing files. Before editing, read the file and copy `oldText` verbatim from its actual current content \u2014 exact characters matter, including quote style (full-width vs ASCII) and version strings. Include enough surrounding lines to make the match unique.");
|
|
14605
14607
|
addToolRule(rules, toolNames, "ApplyPatch", "Use `ApplyPatch` only when an edit genuinely spans multiple regions of one file; hunks may relocate only when their exact context has one unique nearby match. Prefer `Edit` for a single small replacement \u2014 it is easier to get right.");
|
|
14606
|
-
addToolRule(rules, toolNames, "Glob", "Use `Glob` to find files by path pattern instead of shell directory crawling. Confirm the exact path before reading, searching, or editing; the search scope is limited to the workspace, so never pass absolute paths outside it.");
|
|
14607
|
-
addToolRule(rules, toolNames, "Grep", "Use `Grep` to search file contents instead of shell text-search commands.");
|
|
14608
|
+
addToolRule(rules, toolNames, "Glob", "Use `Glob` to find files by path pattern instead of shell directory crawling. Confirm the exact path before reading, searching, or editing; the search scope is limited to the workspace, so never pass absolute paths outside it. Set `includeIgnored: true` only when the user explicitly asks to inspect ignored files or an ignored path is required for the task.");
|
|
14609
|
+
addToolRule(rules, toolNames, "Grep", "Use `Grep` to search file contents instead of shell text-search commands. Set `includeIgnored: true` only when the user explicitly asks to inspect ignored files or an ignored path is required for the task.");
|
|
14608
14610
|
addToolRule(rules, toolNames, "Shell", "Use `Shell` for builds, tests, Git inspection, and commands without a dedicated tool. Keep commands scoped, non-interactive, and easy to audit.");
|
|
14609
14611
|
addToolRule(rules, toolNames, "LspFindRefs", "Use `LspFindRefs` to find all references to a symbol using the Language Server Protocol. Prefer this over Grep when you need precise semantic results.");
|
|
14610
14612
|
addToolRule(rules, toolNames, "LspHover", "Use `LspHover` to get type information and documentation for a symbol at a cursor position.");
|
|
@@ -17894,9 +17896,17 @@ var FILE_TYPE_EXTENSIONS = {
|
|
|
17894
17896
|
python: [".py", ".pyi"],
|
|
17895
17897
|
typescript: [".ts", ".tsx", ".mts", ".cts"]
|
|
17896
17898
|
};
|
|
17899
|
+
var BooleanInput = z30.preprocess((value) => {
|
|
17900
|
+
if (typeof value !== "string") return value;
|
|
17901
|
+
const normalized = value.trim().toLowerCase();
|
|
17902
|
+
if (normalized === "true") return true;
|
|
17903
|
+
if (normalized === "false") return false;
|
|
17904
|
+
return value;
|
|
17905
|
+
}, z30.boolean());
|
|
17897
17906
|
var GlobInput = z30.object({
|
|
17898
17907
|
pattern: z30.string().min(1),
|
|
17899
17908
|
path: z30.string().min(1).describe('Workspace-relative search directory. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
17909
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
17900
17910
|
limit: z30.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
17901
17911
|
});
|
|
17902
17912
|
var GrepInput = z30.object({
|
|
@@ -17904,6 +17914,7 @@ var GrepInput = z30.object({
|
|
|
17904
17914
|
path: z30.string().min(1).describe('Workspace-relative search path. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
17905
17915
|
glob: z30.string().min(1).nullable().optional(),
|
|
17906
17916
|
fileType: z30.enum(FILE_TYPES).nullable().optional(),
|
|
17917
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
17907
17918
|
context: z30.coerce.number().int().nonnegative().max(100).nullable().optional(),
|
|
17908
17919
|
limit: z30.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
17909
17920
|
});
|
|
@@ -17917,23 +17928,26 @@ function createGlobTool(workspace, options = {}) {
|
|
|
17917
17928
|
paths: (input) => [scope(root, searchPath(input.path))],
|
|
17918
17929
|
summarize: (input) => {
|
|
17919
17930
|
const path = searchPath(input.path);
|
|
17920
|
-
|
|
17931
|
+
const ignored2 = input.includeIgnored === true ? " (including ignored files)" : "";
|
|
17932
|
+
return (path ? `pattern: "${input.pattern}" in ${path}` : `pattern: "${input.pattern}"`) + ignored2;
|
|
17921
17933
|
},
|
|
17922
17934
|
execute: async (input, signal) => {
|
|
17923
17935
|
const limit = input.limit ?? options.defaultLimit ?? DEFAULT_RESULT_LIMIT;
|
|
17924
17936
|
const start = scope(root, searchPath(input.path));
|
|
17937
|
+
if (isGitMetadataPath(root, start)) return { matches: [], truncated: false };
|
|
17925
17938
|
const matcher = globRegex(input.pattern);
|
|
17926
17939
|
const ignoreBudget = createIgnoreBudget(resources);
|
|
17940
|
+
const includeIgnored = input.includeIgnored === true;
|
|
17927
17941
|
let paths;
|
|
17928
17942
|
if (options.forceNode === true) {
|
|
17929
|
-
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, ignoreBudget);
|
|
17943
|
+
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, ignoreBudget, includeIgnored);
|
|
17930
17944
|
} else {
|
|
17931
17945
|
try {
|
|
17932
|
-
paths = await rgFiles(root, start, input.pattern, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
17946
|
+
paths = await rgFiles(root, start, input.pattern, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget, includeIgnored);
|
|
17933
17947
|
} catch (error) {
|
|
17934
17948
|
if (signal.aborted) throw signal.reason;
|
|
17935
17949
|
if (!(error instanceof SearchSpawnError) || !error.fallbackSafe) throw error;
|
|
17936
|
-
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, createIgnoreBudget(resources));
|
|
17950
|
+
paths = await nodeFiles(root, start, signal, (path) => matcher.test(path), limit + 1, resources, createIgnoreBudget(resources), includeIgnored);
|
|
17937
17951
|
}
|
|
17938
17952
|
}
|
|
17939
17953
|
const matches = paths.filter((path) => matcher.test(path)).sort(comparePaths);
|
|
@@ -17953,24 +17967,27 @@ function createGrepTool(workspace, options = {}) {
|
|
|
17953
17967
|
const path = searchPath(input.path);
|
|
17954
17968
|
const where = path ? ` in ${path}` : "";
|
|
17955
17969
|
const kind = input.fileType ? ` [${input.fileType}]` : "";
|
|
17956
|
-
|
|
17970
|
+
const ignored2 = input.includeIgnored === true ? " (including ignored files)" : "";
|
|
17971
|
+
return `pattern: /${input.pattern}/${kind}${where}${ignored2}`;
|
|
17957
17972
|
},
|
|
17958
17973
|
execute: async (input, signal) => {
|
|
17959
17974
|
const expression = new RegExp(input.pattern);
|
|
17960
17975
|
const limit = input.limit ?? options.defaultLimit ?? DEFAULT_RESULT_LIMIT;
|
|
17961
17976
|
const context = input.context ?? 0;
|
|
17962
17977
|
const start = await resolveGrepPath(root, searchPath(input.path));
|
|
17978
|
+
if (isGitMetadataPath(root, start)) return { matches: [], truncated: false };
|
|
17963
17979
|
const ignoreBudget = createIgnoreBudget(resources);
|
|
17980
|
+
const includeIgnored = input.includeIgnored === true;
|
|
17964
17981
|
let matches;
|
|
17965
17982
|
if (options.forceNode === true) {
|
|
17966
|
-
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
17983
|
+
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget, includeIgnored);
|
|
17967
17984
|
} else {
|
|
17968
17985
|
try {
|
|
17969
17986
|
matches = await rgGrep(root, start, input, context, signal, options.rgPath ?? bundledRgPath, options.rgArgsPrefix ?? [], limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, ignoreBudget);
|
|
17970
17987
|
} catch (error) {
|
|
17971
17988
|
if (signal.aborted) throw signal.reason;
|
|
17972
17989
|
if (!(error instanceof SearchSpawnError) || !error.fallbackSafe) throw error;
|
|
17973
|
-
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, createIgnoreBudget(resources));
|
|
17990
|
+
matches = await nodeGrep(root, start, input.glob ?? void 0, input.fileType ?? void 0, expression, context, signal, limit + 1, options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES, options.maxSearchBytes ?? DEFAULT_MAX_SEARCH_BYTES, resources, createIgnoreBudget(resources), includeIgnored);
|
|
17974
17991
|
}
|
|
17975
17992
|
}
|
|
17976
17993
|
matches.sort(compareGrepMatches);
|
|
@@ -17978,10 +17995,10 @@ function createGrepTool(workspace, options = {}) {
|
|
|
17978
17995
|
}
|
|
17979
17996
|
};
|
|
17980
17997
|
}
|
|
17981
|
-
async function rgFiles(root, start, pattern, signal, executable, argsPrefix, limit, maxBytes, resources, ignoreBudget) {
|
|
17998
|
+
async function rgFiles(root, start, pattern, signal, executable, argsPrefix, limit, maxBytes, resources, ignoreBudget, includeIgnored) {
|
|
17982
17999
|
const target = relative17(root, start) || ".";
|
|
17983
18000
|
const matcher = globRegex(pattern);
|
|
17984
|
-
const ignoreLayers = await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
18001
|
+
const ignoreLayers = includeIgnored ? [] : await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
17985
18002
|
const paths = [];
|
|
17986
18003
|
const parser = delimitedParser(0, (record3) => {
|
|
17987
18004
|
if (record3.length === 0) return true;
|
|
@@ -17990,7 +18007,10 @@ async function rgFiles(root, start, pattern, signal, executable, argsPrefix, lim
|
|
|
17990
18007
|
retainTopK(paths, path, limit, comparePaths);
|
|
17991
18008
|
return true;
|
|
17992
18009
|
});
|
|
17993
|
-
const
|
|
18010
|
+
const args = [...argsPrefix, "--files", "--null", "--sort", "path", "--hidden", "--glob", "!.git", "--glob", "!.git/**"];
|
|
18011
|
+
if (includeIgnored) args.push("--no-ignore");
|
|
18012
|
+
args.push("--glob", pattern, "--", target);
|
|
18013
|
+
const output = await runStreaming(executable, args, root, signal, maxBytes, parser);
|
|
17994
18014
|
if (!output.stoppedEarly && output.code !== 0 && output.code !== 1) throw new Error(output.stderr || `ripgrep exited with ${output.code}`);
|
|
17995
18015
|
parser.finish();
|
|
17996
18016
|
return paths;
|
|
@@ -18000,12 +18020,13 @@ async function rgGrep(root, start, input, context, signal, executable, argsPrefi
|
|
|
18000
18020
|
if (input.fileType !== void 0 && input.fileType !== null && typeExtensions === void 0) {
|
|
18001
18021
|
throw new Error(`Unsupported file type: ${input.fileType}`);
|
|
18002
18022
|
}
|
|
18003
|
-
const args = ["--json", "--line-number", "--column", "--sort", "path", "--hidden", "--glob", "!.git", "--max-filesize", String(maxFileBytes), "--context", String(context)];
|
|
18023
|
+
const args = ["--json", "--line-number", "--column", "--sort", "path", "--hidden", "--glob", "!.git", "--glob", "!.git/**", "--max-filesize", String(maxFileBytes), "--context", String(context)];
|
|
18024
|
+
if (input.includeIgnored === true) args.push("--no-ignore");
|
|
18004
18025
|
if (input.glob !== void 0 && input.glob !== null) args.push("--glob", input.glob);
|
|
18005
18026
|
else for (const extension2 of typeExtensions ?? []) args.push("--glob", `*${extension2}`);
|
|
18006
18027
|
args.push("--regexp", input.pattern, "--", relative17(root, start) || ".");
|
|
18007
18028
|
const matches = [];
|
|
18008
|
-
const ignoreLayers = await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
18029
|
+
const ignoreLayers = input.includeIgnored === true ? [] : await collectIgnoreLayers(root, start, signal, resources, ignoreBudget);
|
|
18009
18030
|
const parser = delimitedParser(10, (record3) => {
|
|
18010
18031
|
if (record3.length === 0) return true;
|
|
18011
18032
|
const event = JSON.parse(decodeUtf82(record3, "ripgrep JSON"));
|
|
@@ -18060,8 +18081,8 @@ async function hydrateContext(root, matches, context, signal, maxFileBytes, maxT
|
|
|
18060
18081
|
}
|
|
18061
18082
|
}
|
|
18062
18083
|
}
|
|
18063
|
-
async function nodeGrep(root, start, glob, type, expression, context, signal, maxMatches, maxFileBytes, maxSearchBytes, resources, ignoreBudget) {
|
|
18064
|
-
const files = await nodeFiles(root, start, signal, () => true, resources.maxDiscoveredFiles + 1, resources, ignoreBudget);
|
|
18084
|
+
async function nodeGrep(root, start, glob, type, expression, context, signal, maxMatches, maxFileBytes, maxSearchBytes, resources, ignoreBudget, includeIgnored) {
|
|
18085
|
+
const files = await nodeFiles(root, start, signal, () => true, resources.maxDiscoveredFiles + 1, resources, ignoreBudget, includeIgnored);
|
|
18065
18086
|
if (files.length > resources.maxDiscoveredFiles) throw new Error(`Aggregate discovered file limit of ${resources.maxDiscoveredFiles} exceeded`);
|
|
18066
18087
|
const matcher = glob === void 0 ? void 0 : globRegex(glob);
|
|
18067
18088
|
const extension2 = type === void 0 ? void 0 : typeExtension(type);
|
|
@@ -18103,23 +18124,25 @@ async function nodeGrep(root, start, glob, type, expression, context, signal, ma
|
|
|
18103
18124
|
}
|
|
18104
18125
|
return matches;
|
|
18105
18126
|
}
|
|
18106
|
-
async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBudget) {
|
|
18127
|
+
async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBudget, includeIgnored) {
|
|
18107
18128
|
const ignores = [];
|
|
18108
18129
|
const output = [];
|
|
18109
18130
|
const delta = relative17(root, start);
|
|
18110
18131
|
const segments = delta === "" ? [] : delta.split(sep17);
|
|
18111
18132
|
let ancestor = root;
|
|
18112
|
-
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18133
|
+
if (!includeIgnored) {
|
|
18134
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
18135
|
+
noteIgnoreDirectory(ignoreBudget);
|
|
18136
|
+
await loadIgnoreFiles(ancestor, normalizedRelative(root, ancestor), ignores, ignoreBudget, signal);
|
|
18137
|
+
ancestor = resolve24(ancestor, segments[index]);
|
|
18138
|
+
}
|
|
18116
18139
|
}
|
|
18117
18140
|
async function walk(directory) {
|
|
18118
18141
|
abort(signal);
|
|
18119
18142
|
const relativeDirectory = normalizedRelative(root, directory);
|
|
18120
18143
|
const ruleCount = ignores.length;
|
|
18121
18144
|
noteIgnoreDirectory(ignoreBudget);
|
|
18122
|
-
await loadIgnoreFiles(directory, relativeDirectory, ignores, ignoreBudget, signal);
|
|
18145
|
+
if (!includeIgnored) await loadIgnoreFiles(directory, relativeDirectory, ignores, ignoreBudget, signal);
|
|
18123
18146
|
const handle = await opendir(directory);
|
|
18124
18147
|
const entries = [];
|
|
18125
18148
|
for await (const entry2 of handle) {
|
|
@@ -18132,7 +18155,7 @@ async function nodeFiles(root, start, signal, accept, limit, resources, ignoreBu
|
|
|
18132
18155
|
abort(signal);
|
|
18133
18156
|
const absolute = resolve24(directory, entry2.name);
|
|
18134
18157
|
const path = normalizedRelative(root, absolute);
|
|
18135
|
-
if (entry2.name === ".git" || ignored(path, entry2.isDirectory(), ignores)) continue;
|
|
18158
|
+
if (entry2.name === ".git" || !includeIgnored && ignored(path, entry2.isDirectory(), ignores)) continue;
|
|
18136
18159
|
if (entry2.isDirectory()) await walk(absolute);
|
|
18137
18160
|
else if (entry2.isFile() && accept(path)) output.push(path);
|
|
18138
18161
|
if (output.length >= limit) break;
|
|
@@ -18301,6 +18324,9 @@ function normalizedRelative(root, path) {
|
|
|
18301
18324
|
function normalizePath(path) {
|
|
18302
18325
|
return path.replaceAll("\\", "/");
|
|
18303
18326
|
}
|
|
18327
|
+
function isGitMetadataPath(root, path) {
|
|
18328
|
+
return normalizedRelative(root, path).split("/").some((segment) => segment.toLowerCase() === ".git");
|
|
18329
|
+
}
|
|
18304
18330
|
function comparePaths(a, b) {
|
|
18305
18331
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
18306
18332
|
}
|
|
@@ -26341,7 +26367,7 @@ ${expandSkillArguments(await skills.loadBody(skill), prompt)}`);
|
|
|
26341
26367
|
...additionalContext === void 0 ? {} : { additionalContext },
|
|
26342
26368
|
...getSteeringMessages === void 0 ? {} : { getSteeringMessages }
|
|
26343
26369
|
})) {
|
|
26344
|
-
if (event.type === "error" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
26370
|
+
if (event.type === "error" && event.error.code !== "network" && event.error.code !== "rate_limit" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
26345
26371
|
yield { ...event, error: {
|
|
26346
26372
|
...event.error,
|
|
26347
26373
|
message: `${event.error.message}. Configure providers and agents in .flavor/flavor.json or set OPENAI_API_KEY/ANTHROPIC_API_KEY.`
|
package/dist/sdk/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
FlavorRpcServer,
|
|
5
5
|
TraceRecordSchema,
|
|
6
6
|
TraceRecorder
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-T2ARW6CZ.js";
|
|
8
8
|
import {
|
|
9
9
|
AgentMessageQueue,
|
|
10
10
|
DockerExecutionEnvironment,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
WorkspaceCheckpointStore,
|
|
14
14
|
buildDockerInvocation,
|
|
15
15
|
createProductionRuntime
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-Y3DPUAEJ.js";
|
|
17
17
|
import "../chunk-IG4Z23CL.js";
|
|
18
18
|
import "../chunk-RQTYHUMK.js";
|
|
19
19
|
import "../chunk-S32JRDZK.js";
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
3
3
|
declare const GlobInput: z.ZodObject<{
|
|
4
4
|
pattern: z.ZodString;
|
|
5
5
|
path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
6
|
+
includeIgnored: z.ZodOptional<z.ZodNullable<z.ZodPreprocess<z.ZodBoolean>>>;
|
|
6
7
|
limit: z.ZodOptional<z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
|
|
7
8
|
}, z.core.$strip>;
|
|
8
9
|
declare const GrepInput: z.ZodObject<{
|
|
@@ -40,6 +41,7 @@ declare const GrepInput: z.ZodObject<{
|
|
|
40
41
|
xml: "xml";
|
|
41
42
|
yaml: "yaml";
|
|
42
43
|
}>>>;
|
|
44
|
+
includeIgnored: z.ZodOptional<z.ZodNullable<z.ZodPreprocess<z.ZodBoolean>>>;
|
|
43
45
|
context: z.ZodOptional<z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
|
|
44
46
|
limit: z.ZodOptional<z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
|
|
45
47
|
}, z.core.$strip>;
|