@wrongstack/tools 0.300.0 → 0.302.0
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/audit.js +1 -1
- package/dist/batch-tool-use.js +3 -1
- package/dist/browser/index.js +1 -1
- package/dist/builtin.d.ts +3 -2
- package/dist/builtin.js +311 -84
- package/dist/codebase-index/bm25.d.ts +7 -1
- package/dist/codebase-index/index.js +23 -13
- package/dist/codebase-index/project-server.js +23 -13
- package/dist/codebase-index/worker.js +20 -12
- package/dist/format.js +1 -1
- package/dist/git.js +2 -5
- package/dist/glob.js +2 -2
- package/dist/grep.js +118 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +423 -91
- package/dist/install.js +1 -1
- package/dist/json.js +81 -0
- package/dist/languages/index.js +1 -1
- package/dist/lint.js +1 -1
- package/dist/logs.js +81 -0
- package/dist/next-steps-tool.d.ts +26 -0
- package/dist/outdated.js +1 -1
- package/dist/pack.js +311 -84
- package/dist/patch.js +206 -45
- package/dist/read.js +23 -13
- package/dist/replace.js +81 -0
- package/dist/skill.js +51 -2
- package/dist/test.js +1 -1
- package/dist/tool-help.js +2 -2
- package/dist/tool-search.js +1 -1
- package/dist/tool-tier.d.ts +1 -1
- package/dist/tool-tier.js +312 -101
- package/dist/tool-use.js +1 -1
- package/dist/tree.js +13 -3
- package/dist/typecheck.js +1 -1
- package/package.json +3 -3
|
@@ -995,16 +995,23 @@ function looksBinary(content) {
|
|
|
995
995
|
}
|
|
996
996
|
return bad / sample.length > 0.1;
|
|
997
997
|
}
|
|
998
|
-
function
|
|
999
|
-
|
|
1000
|
-
let
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
998
|
+
function newlineOffsets2(content) {
|
|
999
|
+
const offsets = [];
|
|
1000
|
+
for (let i = 0; i < content.length; i++) {
|
|
1001
|
+
if (content.charCodeAt(i) === 10) offsets.push(i);
|
|
1002
|
+
}
|
|
1003
|
+
return offsets;
|
|
1004
|
+
}
|
|
1005
|
+
function lineColAt(offsets, index) {
|
|
1006
|
+
let low = 0;
|
|
1007
|
+
let high = offsets.length;
|
|
1008
|
+
while (low < high) {
|
|
1009
|
+
const mid = low + high >>> 1;
|
|
1010
|
+
if ((offsets[mid] ?? 0) < index) low = mid + 1;
|
|
1011
|
+
else high = mid;
|
|
1006
1012
|
}
|
|
1007
|
-
|
|
1013
|
+
const lastNl = low > 0 ? offsets[low - 1] : -1;
|
|
1014
|
+
return { line: low + 1, col: index - lastNl };
|
|
1008
1015
|
}
|
|
1009
1016
|
function parseGeneric(opts) {
|
|
1010
1017
|
const { file, lang } = opts;
|
|
@@ -1017,6 +1024,7 @@ function parseGeneric(opts) {
|
|
|
1017
1024
|
const patterns = patternsFor(lang);
|
|
1018
1025
|
const symbols = [];
|
|
1019
1026
|
const seen = /* @__PURE__ */ new Set();
|
|
1027
|
+
const nlOffsets = newlineOffsets2(content);
|
|
1020
1028
|
for (const pattern of patterns) {
|
|
1021
1029
|
const re = new RegExp(pattern.re.source, pattern.re.flags.includes("g") ? pattern.re.flags : `${pattern.re.flags}g`);
|
|
1022
1030
|
re.lastIndex = 0;
|
|
@@ -1030,7 +1038,7 @@ function parseGeneric(opts) {
|
|
|
1030
1038
|
if (!/^[A-Za-z_#.@/\w][\w.\-:/#!?]*$/.test(name) && lang !== "md" && lang !== "toml") {
|
|
1031
1039
|
continue;
|
|
1032
1040
|
}
|
|
1033
|
-
const { line, col } = lineColAt(
|
|
1041
|
+
const { line, col } = lineColAt(nlOffsets, match.index ?? 0);
|
|
1034
1042
|
const key = `${name}\0${line}\0${pattern.kind}`;
|
|
1035
1043
|
if (seen.has(key)) continue;
|
|
1036
1044
|
seen.add(key);
|
|
@@ -2228,9 +2236,9 @@ import * as path4 from "node:path";
|
|
|
2228
2236
|
// src/codebase-index/bm25.ts
|
|
2229
2237
|
var K1 = 1.5;
|
|
2230
2238
|
var B = 0.75;
|
|
2239
|
+
var TOKENISE_RE = new RegExp("[^\\p{L}\\p{N}$']", "gu");
|
|
2231
2240
|
function tokenise(text) {
|
|
2232
|
-
|
|
2233
|
-
return sanitised.toLowerCase().split(" ").filter(Boolean);
|
|
2241
|
+
return text.replace(TOKENISE_RE, " ").toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
2234
2242
|
}
|
|
2235
2243
|
function splitName(name) {
|
|
2236
2244
|
return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([\p{L}])(\d)/gu, "$1 $2").replace(/(\d)([\p{L}])/gu, "$1 $2").replace(/[_-]+/g, " ").trim();
|
|
@@ -4745,7 +4753,9 @@ var PROJECT_INDEX_SERVER_METADATA_FILE = "server.json";
|
|
|
4745
4753
|
var PROJECT_INDEX_SERVER_SOCKET_DIR = `wsci-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`;
|
|
4746
4754
|
var buildIdCache;
|
|
4747
4755
|
function projectIndexServerBuildId(entrypoint) {
|
|
4748
|
-
const
|
|
4756
|
+
const href = entrypoint instanceof URL ? entrypoint.href : entrypoint;
|
|
4757
|
+
const cleanHref = href.split(/[?#]/, 1)[0] ?? href;
|
|
4758
|
+
const file = cleanHref.startsWith("file:") ? fileURLToPath(cleanHref) : path5.resolve(cleanHref);
|
|
4749
4759
|
try {
|
|
4750
4760
|
const stat2 = fs4.statSync(file);
|
|
4751
4761
|
if (buildIdCache?.file === file && buildIdCache.mtimeMs === stat2.mtimeMs && buildIdCache.size === stat2.size) {
|
|
@@ -996,16 +996,23 @@ function looksBinary(content) {
|
|
|
996
996
|
}
|
|
997
997
|
return bad / sample.length > 0.1;
|
|
998
998
|
}
|
|
999
|
-
function
|
|
1000
|
-
|
|
1001
|
-
let
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
999
|
+
function newlineOffsets2(content) {
|
|
1000
|
+
const offsets = [];
|
|
1001
|
+
for (let i = 0; i < content.length; i++) {
|
|
1002
|
+
if (content.charCodeAt(i) === 10) offsets.push(i);
|
|
1003
|
+
}
|
|
1004
|
+
return offsets;
|
|
1005
|
+
}
|
|
1006
|
+
function lineColAt(offsets, index) {
|
|
1007
|
+
let low = 0;
|
|
1008
|
+
let high = offsets.length;
|
|
1009
|
+
while (low < high) {
|
|
1010
|
+
const mid = low + high >>> 1;
|
|
1011
|
+
if ((offsets[mid] ?? 0) < index) low = mid + 1;
|
|
1012
|
+
else high = mid;
|
|
1007
1013
|
}
|
|
1008
|
-
|
|
1014
|
+
const lastNl = low > 0 ? offsets[low - 1] : -1;
|
|
1015
|
+
return { line: low + 1, col: index - lastNl };
|
|
1009
1016
|
}
|
|
1010
1017
|
function parseGeneric(opts) {
|
|
1011
1018
|
const { file, lang } = opts;
|
|
@@ -1018,6 +1025,7 @@ function parseGeneric(opts) {
|
|
|
1018
1025
|
const patterns = patternsFor(lang);
|
|
1019
1026
|
const symbols = [];
|
|
1020
1027
|
const seen = /* @__PURE__ */ new Set();
|
|
1028
|
+
const nlOffsets = newlineOffsets2(content);
|
|
1021
1029
|
for (const pattern of patterns) {
|
|
1022
1030
|
const re = new RegExp(pattern.re.source, pattern.re.flags.includes("g") ? pattern.re.flags : `${pattern.re.flags}g`);
|
|
1023
1031
|
re.lastIndex = 0;
|
|
@@ -1031,7 +1039,7 @@ function parseGeneric(opts) {
|
|
|
1031
1039
|
if (!/^[A-Za-z_#.@/\w][\w.\-:/#!?]*$/.test(name) && lang !== "md" && lang !== "toml") {
|
|
1032
1040
|
continue;
|
|
1033
1041
|
}
|
|
1034
|
-
const { line, col } = lineColAt(
|
|
1042
|
+
const { line, col } = lineColAt(nlOffsets, match.index ?? 0);
|
|
1035
1043
|
const key = `${name}\0${line}\0${pattern.kind}`;
|
|
1036
1044
|
if (seen.has(key)) continue;
|
|
1037
1045
|
seen.add(key);
|
|
@@ -2987,9 +2995,9 @@ import * as path10 from "node:path";
|
|
|
2987
2995
|
// src/codebase-index/bm25.ts
|
|
2988
2996
|
var K1 = 1.5;
|
|
2989
2997
|
var B = 0.75;
|
|
2998
|
+
var TOKENISE_RE = new RegExp("[^\\p{L}\\p{N}$']", "gu");
|
|
2990
2999
|
function tokenise(text) {
|
|
2991
|
-
|
|
2992
|
-
return sanitised.toLowerCase().split(" ").filter(Boolean);
|
|
3000
|
+
return text.replace(TOKENISE_RE, " ").toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
2993
3001
|
}
|
|
2994
3002
|
function splitName(name) {
|
|
2995
3003
|
return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([\p{L}])(\d)/gu, "$1 $2").replace(/(\d)([\p{L}])/gu, "$1 $2").replace(/[_-]+/g, " ").trim();
|
|
@@ -5837,7 +5845,9 @@ var PROJECT_INDEX_SERVER_METADATA_FILE = "server.json";
|
|
|
5837
5845
|
var PROJECT_INDEX_SERVER_SOCKET_DIR = `wsci-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`;
|
|
5838
5846
|
var buildIdCache;
|
|
5839
5847
|
function projectIndexServerBuildId(entrypoint) {
|
|
5840
|
-
const
|
|
5848
|
+
const href = entrypoint instanceof URL ? entrypoint.href : entrypoint;
|
|
5849
|
+
const cleanHref = href.split(/[?#]/, 1)[0] ?? href;
|
|
5850
|
+
const file = cleanHref.startsWith("file:") ? fileURLToPath(cleanHref) : path12.resolve(cleanHref);
|
|
5841
5851
|
try {
|
|
5842
5852
|
const stat2 = fs9.statSync(file);
|
|
5843
5853
|
if (buildIdCache?.file === file && buildIdCache.mtimeMs === stat2.mtimeMs && buildIdCache.size === stat2.size) {
|
|
@@ -992,16 +992,23 @@ function looksBinary(content) {
|
|
|
992
992
|
}
|
|
993
993
|
return bad / sample.length > 0.1;
|
|
994
994
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
997
|
-
let
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
995
|
+
function newlineOffsets2(content) {
|
|
996
|
+
const offsets = [];
|
|
997
|
+
for (let i = 0; i < content.length; i++) {
|
|
998
|
+
if (content.charCodeAt(i) === 10) offsets.push(i);
|
|
999
|
+
}
|
|
1000
|
+
return offsets;
|
|
1001
|
+
}
|
|
1002
|
+
function lineColAt(offsets, index) {
|
|
1003
|
+
let low = 0;
|
|
1004
|
+
let high = offsets.length;
|
|
1005
|
+
while (low < high) {
|
|
1006
|
+
const mid = low + high >>> 1;
|
|
1007
|
+
if ((offsets[mid] ?? 0) < index) low = mid + 1;
|
|
1008
|
+
else high = mid;
|
|
1003
1009
|
}
|
|
1004
|
-
|
|
1010
|
+
const lastNl = low > 0 ? offsets[low - 1] : -1;
|
|
1011
|
+
return { line: low + 1, col: index - lastNl };
|
|
1005
1012
|
}
|
|
1006
1013
|
function parseGeneric(opts) {
|
|
1007
1014
|
const { file, lang } = opts;
|
|
@@ -1014,6 +1021,7 @@ function parseGeneric(opts) {
|
|
|
1014
1021
|
const patterns = patternsFor(lang);
|
|
1015
1022
|
const symbols = [];
|
|
1016
1023
|
const seen = /* @__PURE__ */ new Set();
|
|
1024
|
+
const nlOffsets = newlineOffsets2(content);
|
|
1017
1025
|
for (const pattern of patterns) {
|
|
1018
1026
|
const re = new RegExp(pattern.re.source, pattern.re.flags.includes("g") ? pattern.re.flags : `${pattern.re.flags}g`);
|
|
1019
1027
|
re.lastIndex = 0;
|
|
@@ -1027,7 +1035,7 @@ function parseGeneric(opts) {
|
|
|
1027
1035
|
if (!/^[A-Za-z_#.@/\w][\w.\-:/#!?]*$/.test(name) && lang !== "md" && lang !== "toml") {
|
|
1028
1036
|
continue;
|
|
1029
1037
|
}
|
|
1030
|
-
const { line, col } = lineColAt(
|
|
1038
|
+
const { line, col } = lineColAt(nlOffsets, match.index ?? 0);
|
|
1031
1039
|
const key = `${name}\0${line}\0${pattern.kind}`;
|
|
1032
1040
|
if (seen.has(key)) continue;
|
|
1033
1041
|
seen.add(key);
|
|
@@ -2974,9 +2982,9 @@ import * as path10 from "node:path";
|
|
|
2974
2982
|
// src/codebase-index/bm25.ts
|
|
2975
2983
|
var K1 = 1.5;
|
|
2976
2984
|
var B = 0.75;
|
|
2985
|
+
var TOKENISE_RE = new RegExp("[^\\p{L}\\p{N}$']", "gu");
|
|
2977
2986
|
function tokenise(text) {
|
|
2978
|
-
|
|
2979
|
-
return sanitised.toLowerCase().split(" ").filter(Boolean);
|
|
2987
|
+
return text.replace(TOKENISE_RE, " ").toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
2980
2988
|
}
|
|
2981
2989
|
function splitName(name) {
|
|
2982
2990
|
return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([\p{L}])(\d)/gu, "$1 $2").replace(/(\d)([\p{L}])/gu, "$1 $2").replace(/[_-]+/g, " ").trim();
|
package/dist/format.js
CHANGED
|
@@ -792,7 +792,7 @@ function getProcessRegistry() {
|
|
|
792
792
|
// src/_spawn-stream.ts
|
|
793
793
|
var isWin = process.platform === "win32";
|
|
794
794
|
async function* spawnStream(opts) {
|
|
795
|
-
const max = opts.maxBytes ??
|
|
795
|
+
const max = opts.maxBytes ?? 999999999;
|
|
796
796
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
797
797
|
const maxQueue = opts.maxQueueSize ?? 500;
|
|
798
798
|
const maxQueueBytes = opts.maxQueueBytes ?? 1024 * 1024;
|
package/dist/git.js
CHANGED
|
@@ -291,11 +291,8 @@ function buildArgs(input) {
|
|
|
291
291
|
...input.branch.startsWith("-") || input.branch.includes(" --") ? [] : [input.branch]
|
|
292
292
|
] : ["branch"];
|
|
293
293
|
case "checkout":
|
|
294
|
-
return [
|
|
295
|
-
|
|
296
|
-
...input.branch ? ["--", input.branch] : [],
|
|
297
|
-
...files.length ? ["--", ...files] : []
|
|
298
|
-
];
|
|
294
|
+
if (files.length) return ["checkout", "--", ...files];
|
|
295
|
+
return input.branch ? ["checkout", input.branch, "--"] : ["checkout"];
|
|
299
296
|
case "stash":
|
|
300
297
|
return input.message ? ["stash", "push", "-m", input.message] : ["stash", "push"];
|
|
301
298
|
case "push":
|
package/dist/glob.js
CHANGED
|
@@ -138,7 +138,7 @@ async function safeResolveReal(input, ctx) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
// src/glob.ts
|
|
141
|
-
var DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;
|
|
141
|
+
var DEFAULT_IGNORE = new Set(DEFAULT_WALK_IGNORE_DIRS);
|
|
142
142
|
var WALK_CONCURRENCY = 16;
|
|
143
143
|
var globTool = {
|
|
144
144
|
name: "glob",
|
|
@@ -217,7 +217,7 @@ var globTool = {
|
|
|
217
217
|
const matchedFiles = [];
|
|
218
218
|
for (const e of entries) {
|
|
219
219
|
const name = e.name;
|
|
220
|
-
if (DEFAULT_IGNORE.
|
|
220
|
+
if (DEFAULT_IGNORE.has(name)) continue;
|
|
221
221
|
const rel = relPrefix ? `${relPrefix}/${name}` : name;
|
|
222
222
|
const full = path3.join(dir, name);
|
|
223
223
|
if (e.isDirectory()) {
|
package/dist/grep.js
CHANGED
|
@@ -40,6 +40,81 @@ var DANGEROUS_PATTERNS = [
|
|
|
40
40
|
// Greedy quantifier inside lookahead/lookbehind — (?!.*a+)
|
|
41
41
|
/[([][^)\]]*[+*][^)\]]*[)\]][^)]*\?\??/
|
|
42
42
|
];
|
|
43
|
+
function hasAmbiguousQuantifiedAlternation(pattern) {
|
|
44
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
45
|
+
if (pattern[i] !== "(") continue;
|
|
46
|
+
if (i > 0 && pattern[i - 1] === "\\") continue;
|
|
47
|
+
let depth = 0;
|
|
48
|
+
let inClass = false;
|
|
49
|
+
let j = i;
|
|
50
|
+
for (; j < pattern.length; j++) {
|
|
51
|
+
const ch = pattern[j];
|
|
52
|
+
if (ch === "\\") {
|
|
53
|
+
j++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (inClass) {
|
|
57
|
+
if (ch === "]") inClass = false;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (ch === "[") {
|
|
61
|
+
inClass = true;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (ch === "(") depth++;
|
|
65
|
+
else if (ch === ")") {
|
|
66
|
+
depth--;
|
|
67
|
+
if (depth === 0) break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (j >= pattern.length) return false;
|
|
71
|
+
const next = pattern[j + 1];
|
|
72
|
+
if (next !== "+" && next !== "*" && next !== "{") continue;
|
|
73
|
+
let inner = pattern.slice(i + 1, j);
|
|
74
|
+
inner = inner.replace(/^\?(?::|<?[=!])/u, "");
|
|
75
|
+
const branches = [];
|
|
76
|
+
let current = "";
|
|
77
|
+
let d = 0;
|
|
78
|
+
let cls = false;
|
|
79
|
+
for (let k = 0; k < inner.length; k++) {
|
|
80
|
+
const ch = inner[k];
|
|
81
|
+
if (ch === "\\") {
|
|
82
|
+
current += ch + (inner[k + 1] ?? "");
|
|
83
|
+
k++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (cls) {
|
|
87
|
+
if (ch === "]") cls = false;
|
|
88
|
+
current += ch;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (ch === "[") {
|
|
92
|
+
cls = true;
|
|
93
|
+
current += ch;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (ch === "(") d++;
|
|
97
|
+
if (ch === ")") d--;
|
|
98
|
+
if (ch === "|" && d === 0) {
|
|
99
|
+
branches.push(current);
|
|
100
|
+
current = "";
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
current += ch;
|
|
104
|
+
}
|
|
105
|
+
branches.push(current);
|
|
106
|
+
if (branches.length < 2) continue;
|
|
107
|
+
for (let a = 0; a < branches.length; a++) {
|
|
108
|
+
for (let b = a + 1; b < branches.length; b++) {
|
|
109
|
+
const x = branches[a];
|
|
110
|
+
const y = branches[b];
|
|
111
|
+
if (x === "" || y === "") return true;
|
|
112
|
+
if (x === y || x.startsWith(y) || y.startsWith(x)) return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
43
118
|
function compileUserRegex(pattern, flags) {
|
|
44
119
|
if (typeof pattern !== "string") {
|
|
45
120
|
return { ok: false, reason: "pattern must be a string" };
|
|
@@ -58,6 +133,12 @@ function compileUserRegex(pattern, flags) {
|
|
|
58
133
|
};
|
|
59
134
|
}
|
|
60
135
|
}
|
|
136
|
+
if (hasAmbiguousQuantifiedAlternation(pattern)) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
reason: "pattern quantifies an alternation with overlapping branches \u2014 rewrite so no two branches can match the same text"
|
|
140
|
+
};
|
|
141
|
+
}
|
|
61
142
|
try {
|
|
62
143
|
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
63
144
|
} catch (err) {
|
|
@@ -73,6 +154,7 @@ function capSubject(line) {
|
|
|
73
154
|
}
|
|
74
155
|
|
|
75
156
|
// src/_util.ts
|
|
157
|
+
import * as fsp from "node:fs/promises";
|
|
76
158
|
import * as path from "node:path";
|
|
77
159
|
import * as Core from "@wrongstack/core/utils";
|
|
78
160
|
function resolvePath(input, ctx) {
|
|
@@ -96,6 +178,39 @@ function ensureInsideRoot(absPath, ctx) {
|
|
|
96
178
|
function safeResolve(input, ctx) {
|
|
97
179
|
return ensureInsideRoot(resolvePath(input, ctx), ctx);
|
|
98
180
|
}
|
|
181
|
+
async function resolveRealInsideRoot(absPath, ctx) {
|
|
182
|
+
if (ctx.allowOutsideProjectRoot) return absPath;
|
|
183
|
+
const realRoots = await Promise.all(
|
|
184
|
+
allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r)))
|
|
185
|
+
);
|
|
186
|
+
let probe = absPath;
|
|
187
|
+
const pendingTail = [];
|
|
188
|
+
for (; ; ) {
|
|
189
|
+
let real;
|
|
190
|
+
try {
|
|
191
|
+
real = await fsp.realpath(probe);
|
|
192
|
+
} catch (err) {
|
|
193
|
+
if (err.code === "ENOENT") {
|
|
194
|
+
const parent = path.dirname(probe);
|
|
195
|
+
if (parent === probe) return absPath;
|
|
196
|
+
pendingTail.unshift(path.basename(probe));
|
|
197
|
+
probe = parent;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
if (isInsideAny(real, realRoots)) {
|
|
203
|
+
return pendingTail.length > 0 ? path.join(real, ...pendingTail) : real;
|
|
204
|
+
}
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function safeResolveReal(input, ctx) {
|
|
211
|
+
const abs = safeResolve(input, ctx);
|
|
212
|
+
return await resolveRealInsideRoot(abs, ctx);
|
|
213
|
+
}
|
|
99
214
|
function isBinaryBuffer(buf) {
|
|
100
215
|
const len = Math.min(buf.length, 8192);
|
|
101
216
|
for (let i = 0; i < len; i++) {
|
|
@@ -160,7 +275,7 @@ async function loadGitignoreMatcher(projectRoot) {
|
|
|
160
275
|
}
|
|
161
276
|
|
|
162
277
|
// src/grep.ts
|
|
163
|
-
var DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;
|
|
278
|
+
var DEFAULT_IGNORE = new Set(DEFAULT_WALK_IGNORE_DIRS);
|
|
164
279
|
var NATIVE_SCAN_CONCURRENCY = 32;
|
|
165
280
|
var NATIVE_READ_CHUNK_BYTES = 64 * 1024;
|
|
166
281
|
var NATIVE_MAX_FILE_BYTES = 1e6;
|
|
@@ -233,7 +348,7 @@ var grepTool = {
|
|
|
233
348
|
field: "pattern"
|
|
234
349
|
});
|
|
235
350
|
}
|
|
236
|
-
const base = input.path ?
|
|
351
|
+
const base = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
|
|
237
352
|
const mode = input.output_mode ?? "content";
|
|
238
353
|
const limit = Math.max(1, Math.min(input.limit ?? 200, 2e3));
|
|
239
354
|
const validation = compileUserRegex(input.pattern, input.case_insensitive ? "i" : "");
|
|
@@ -558,7 +673,7 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
558
673
|
const subdirs = [];
|
|
559
674
|
for (const e of entries) {
|
|
560
675
|
if (stopped) return;
|
|
561
|
-
if (DEFAULT_IGNORE.
|
|
676
|
+
if (DEFAULT_IGNORE.has(e.name)) continue;
|
|
562
677
|
if (e.isSymbolicLink()) continue;
|
|
563
678
|
const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
|
|
564
679
|
const full = path3.join(dir, e.name);
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export { lintTool } from './lint.js';
|
|
|
30
30
|
export { logsTool } from './logs.js';
|
|
31
31
|
export { forgetTool, relatedMemoryTool, rememberTool, searchMemoryTool } from './memory.js';
|
|
32
32
|
export { createModeTool } from './mode.js';
|
|
33
|
+
export { nextStepsTool } from './next-steps-tool.js';
|
|
33
34
|
export { outdatedTool } from './outdated.js';
|
|
34
35
|
export { builtinToolsPack } from './pack.js';
|
|
35
36
|
export { patchTool } from './patch.js';
|