@wrongstack/tools 0.273.1 → 0.274.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/builtin.js +166 -70
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +24 -16
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/codebase-index/worker.js +24 -16
- package/dist/codebase-index/worker.js.map +1 -1
- package/dist/glob.js +61 -11
- package/dist/glob.js.map +1 -1
- package/dist/grep.js +92 -39
- package/dist/grep.js.map +1 -1
- package/dist/index.js +166 -70
- package/dist/index.js.map +1 -1
- package/dist/pack.js +166 -70
- package/dist/pack.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -778,7 +778,27 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
778
778
|
await walk(base);
|
|
779
779
|
return results;
|
|
780
780
|
}
|
|
781
|
+
|
|
782
|
+
// src/_concurrency.ts
|
|
783
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
784
|
+
if (items.length === 0) return [];
|
|
785
|
+
const effectiveLimit = Math.max(1, Math.min(limit | 0, items.length));
|
|
786
|
+
const results = new Array(items.length);
|
|
787
|
+
let nextIndex = 0;
|
|
788
|
+
const worker2 = async () => {
|
|
789
|
+
while (true) {
|
|
790
|
+
const i = nextIndex++;
|
|
791
|
+
if (i >= items.length) return;
|
|
792
|
+
results[i] = await fn(items[i]);
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
await Promise.all(Array.from({ length: effectiveLimit }, worker2));
|
|
796
|
+
return results;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// src/glob.ts
|
|
781
800
|
var DEFAULT_IGNORE2 = ["node_modules", ".git", "dist", "build", ".next", "coverage", ".turbo"];
|
|
801
|
+
var WALK_CONCURRENCY = 16;
|
|
782
802
|
var globTool = {
|
|
783
803
|
name: "glob",
|
|
784
804
|
category: "Filesystem",
|
|
@@ -816,6 +836,22 @@ var globTool = {
|
|
|
816
836
|
const re = compileGlob(input.pattern);
|
|
817
837
|
const results = [];
|
|
818
838
|
let truncated = false;
|
|
839
|
+
const pushResult = async (full) => {
|
|
840
|
+
if (truncated || results.length >= limit) {
|
|
841
|
+
truncated = true;
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
845
|
+
const st = await fs7.stat(full);
|
|
846
|
+
if (truncated || results.length >= limit) {
|
|
847
|
+
truncated = true;
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
results.push({ rel: full, mtime: st.mtimeMs });
|
|
851
|
+
if (results.length >= limit) truncated = true;
|
|
852
|
+
} catch {
|
|
853
|
+
}
|
|
854
|
+
};
|
|
819
855
|
const walk = async (dir, relPrefix) => {
|
|
820
856
|
if (results.length >= limit) {
|
|
821
857
|
truncated = true;
|
|
@@ -827,6 +863,8 @@ var globTool = {
|
|
|
827
863
|
} catch {
|
|
828
864
|
return;
|
|
829
865
|
}
|
|
866
|
+
const subdirs = [];
|
|
867
|
+
const matchedFiles = [];
|
|
830
868
|
for (const e of entries) {
|
|
831
869
|
const name = e.name;
|
|
832
870
|
if (DEFAULT_IGNORE2.includes(name)) continue;
|
|
@@ -834,22 +872,36 @@ var globTool = {
|
|
|
834
872
|
const rel = relPrefix ? `${relPrefix}/${name}` : name;
|
|
835
873
|
const full = path.join(dir, name);
|
|
836
874
|
if (e.isDirectory()) {
|
|
837
|
-
|
|
838
|
-
if (truncated) return;
|
|
875
|
+
subdirs.push({ full, rel });
|
|
839
876
|
} else if (e.isFile()) {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
877
|
+
re.lastIndex = 0;
|
|
878
|
+
const relMatch = re.test(rel);
|
|
879
|
+
re.lastIndex = 0;
|
|
880
|
+
const nameMatch = re.test(name);
|
|
881
|
+
if (relMatch || nameMatch) {
|
|
882
|
+
matchedFiles.push(full);
|
|
883
|
+
}
|
|
884
|
+
} else if (e.isSymbolicLink()) {
|
|
885
|
+
try {
|
|
886
|
+
const st = await fs7.stat(full);
|
|
887
|
+
if (st.isDirectory()) {
|
|
888
|
+
subdirs.push({ full, rel });
|
|
889
|
+
} else if (st.isFile()) {
|
|
890
|
+
re.lastIndex = 0;
|
|
891
|
+
const relMatch = re.test(rel);
|
|
892
|
+
re.lastIndex = 0;
|
|
893
|
+
const nameMatch = re.test(name);
|
|
894
|
+
if (relMatch || nameMatch) matchedFiles.push(full);
|
|
849
895
|
}
|
|
896
|
+
} catch {
|
|
850
897
|
}
|
|
851
898
|
}
|
|
899
|
+
if (truncated) return;
|
|
852
900
|
}
|
|
901
|
+
await mapWithConcurrency(matchedFiles, WALK_CONCURRENCY, pushResult);
|
|
902
|
+
if (truncated) return;
|
|
903
|
+
const remainingSubdirs = truncated ? [] : subdirs;
|
|
904
|
+
await mapWithConcurrency(remainingSubdirs, WALK_CONCURRENCY, ({ full, rel }) => walk(full, rel));
|
|
853
905
|
};
|
|
854
906
|
await walk(base, "");
|
|
855
907
|
results.sort((a, b) => b.mtime - a.mtime);
|
|
@@ -866,6 +918,8 @@ async function readGitignore(dir) {
|
|
|
866
918
|
}
|
|
867
919
|
var DEFAULT_IGNORE3 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
868
920
|
var NATIVE_SCAN_CONCURRENCY = 32;
|
|
921
|
+
var NATIVE_READ_CHUNK_BYTES = 64 * 1024;
|
|
922
|
+
var NATIVE_MAX_FILE_BYTES = 1e6;
|
|
869
923
|
var grepTool = {
|
|
870
924
|
name: "grep",
|
|
871
925
|
category: "Search",
|
|
@@ -1090,7 +1144,8 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
1090
1144
|
const re = compiled.regex;
|
|
1091
1145
|
const globRe = input.glob ? compileGlob(input.glob) : null;
|
|
1092
1146
|
const matches = [];
|
|
1093
|
-
const
|
|
1147
|
+
const countOnlyFirstHit = mode === "count" && limit === 1;
|
|
1148
|
+
const maxBytes = mode === "content" ? NATIVE_MAX_FILE_BYTES : Math.min(NATIVE_MAX_FILE_BYTES, 256 * 1024);
|
|
1094
1149
|
let total = 0;
|
|
1095
1150
|
let stopped = false;
|
|
1096
1151
|
const scanFile = async (full, name) => {
|
|
@@ -1099,34 +1154,79 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
1099
1154
|
if (globRe) globRe.lastIndex = 0;
|
|
1100
1155
|
try {
|
|
1101
1156
|
const stat11 = await fs7.stat(full);
|
|
1102
|
-
if (stat11.size >
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
const
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1157
|
+
if (!stat11.isFile() || stat11.size > maxBytes || stopped || signal.aborted) return;
|
|
1158
|
+
const file = await fs7.open(full, "r");
|
|
1159
|
+
try {
|
|
1160
|
+
let bytesReadTotal = 0;
|
|
1161
|
+
let lineNumber = 0;
|
|
1162
|
+
let fileHits = 0;
|
|
1163
|
+
let leftover = "";
|
|
1164
|
+
let binaryChecked = false;
|
|
1165
|
+
const buffer = Buffer.allocUnsafe(Math.min(NATIVE_READ_CHUNK_BYTES, maxBytes));
|
|
1166
|
+
while (!stopped && !signal.aborted && bytesReadTotal < maxBytes) {
|
|
1167
|
+
const remaining = maxBytes - bytesReadTotal;
|
|
1168
|
+
const { bytesRead } = await file.read(buffer, 0, Math.min(buffer.length, remaining), null);
|
|
1169
|
+
if (bytesRead === 0) break;
|
|
1170
|
+
const chunk = buffer.subarray(0, bytesRead);
|
|
1171
|
+
if (!binaryChecked) {
|
|
1172
|
+
binaryChecked = true;
|
|
1173
|
+
if (isBinaryBuffer(chunk)) return;
|
|
1174
|
+
}
|
|
1175
|
+
bytesReadTotal += bytesRead;
|
|
1176
|
+
const text = leftover + chunk.toString("utf8");
|
|
1177
|
+
const lines = text.split(/\r?\n/);
|
|
1178
|
+
leftover = lines.pop() ?? "";
|
|
1179
|
+
for (const rawLine of lines) {
|
|
1180
|
+
if (stopped || signal.aborted) break;
|
|
1181
|
+
lineNumber++;
|
|
1182
|
+
const ln = capSubject(rawLine);
|
|
1183
|
+
re.lastIndex = 0;
|
|
1184
|
+
if (!re.test(ln)) continue;
|
|
1185
|
+
fileHits++;
|
|
1186
|
+
total++;
|
|
1187
|
+
if (mode === "content") {
|
|
1188
|
+
if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);
|
|
1189
|
+
} else if (mode === "files_with_matches") {
|
|
1190
|
+
if (fileHits === 1 && matches.length < limit) matches.push(full);
|
|
1191
|
+
break;
|
|
1192
|
+
} else if (fileHits === 1 && matches.length < limit) {
|
|
1193
|
+
matches.push(`${full}:${countOnlyFirstHit ? 1 : 0}`);
|
|
1194
|
+
}
|
|
1195
|
+
if (countOnlyFirstHit || mode !== "content" && matches.length >= limit) {
|
|
1196
|
+
stopped = true;
|
|
1197
|
+
break;
|
|
1198
|
+
}
|
|
1117
1199
|
}
|
|
1200
|
+
if (mode === "files_with_matches" && fileHits > 0) break;
|
|
1118
1201
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1202
|
+
if (!stopped && !signal.aborted && leftover.length > 0) {
|
|
1203
|
+
lineNumber++;
|
|
1204
|
+
const ln = capSubject(leftover);
|
|
1205
|
+
re.lastIndex = 0;
|
|
1206
|
+
if (re.test(ln)) {
|
|
1207
|
+
fileHits++;
|
|
1208
|
+
total++;
|
|
1209
|
+
if (mode === "content") {
|
|
1210
|
+
if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);
|
|
1211
|
+
} else if (mode === "files_with_matches") {
|
|
1212
|
+
if (matches.length < limit) matches.push(full);
|
|
1213
|
+
} else if (matches.length < limit) {
|
|
1214
|
+
matches.push(`${full}:${countOnlyFirstHit ? 1 : fileHits}`);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1124
1217
|
}
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
1218
|
+
if (fileHits > 0) {
|
|
1219
|
+
if (mode === "count") {
|
|
1220
|
+
const idx = matches.findIndex((entry) => entry.startsWith(`${full}:`));
|
|
1221
|
+
if (idx !== -1) matches[idx] = `${full}:${fileHits}`;
|
|
1222
|
+
}
|
|
1223
|
+
if (mode === "files_with_matches" && matches.length >= limit) stopped = true;
|
|
1127
1224
|
}
|
|
1225
|
+
if (mode === "content" && matches.length >= limit) stopped = true;
|
|
1226
|
+
if (mode === "count" && matches.length >= limit && (countOnlyFirstHit || mode !== "count")) stopped = true;
|
|
1227
|
+
} finally {
|
|
1228
|
+
await file.close();
|
|
1128
1229
|
}
|
|
1129
|
-
if (matches.length >= limit) stopped = true;
|
|
1130
1230
|
} catch {
|
|
1131
1231
|
}
|
|
1132
1232
|
};
|
|
@@ -1139,18 +1239,20 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
1139
1239
|
return;
|
|
1140
1240
|
}
|
|
1141
1241
|
const files = [];
|
|
1242
|
+
const subdirs = [];
|
|
1142
1243
|
for (const e of entries) {
|
|
1143
1244
|
if (stopped) return;
|
|
1144
1245
|
if (DEFAULT_IGNORE3.includes(e.name)) continue;
|
|
1145
1246
|
if (e.isSymbolicLink()) continue;
|
|
1146
1247
|
const full = path.join(dir, e.name);
|
|
1147
1248
|
if (e.isDirectory()) {
|
|
1148
|
-
|
|
1249
|
+
subdirs.push(full);
|
|
1149
1250
|
} else if (e.isFile()) {
|
|
1150
1251
|
files.push({ full, name: e.name });
|
|
1151
1252
|
}
|
|
1152
1253
|
}
|
|
1153
1254
|
await mapWithConcurrency(files, NATIVE_SCAN_CONCURRENCY, ({ full, name }) => scanFile(full, name));
|
|
1255
|
+
await mapWithConcurrency(subdirs, Math.min(16, NATIVE_SCAN_CONCURRENCY), walk);
|
|
1154
1256
|
};
|
|
1155
1257
|
await walk(base);
|
|
1156
1258
|
return {
|
|
@@ -1160,20 +1262,6 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
1160
1262
|
used: "native"
|
|
1161
1263
|
};
|
|
1162
1264
|
}
|
|
1163
|
-
async function mapWithConcurrency(items, concurrency, fn) {
|
|
1164
|
-
if (items.length === 0) return;
|
|
1165
|
-
let next = 0;
|
|
1166
|
-
const workerCount = Math.min(Math.max(1, concurrency), items.length);
|
|
1167
|
-
const workers = Array.from({ length: workerCount }, async () => {
|
|
1168
|
-
for (; ; ) {
|
|
1169
|
-
const idx = next++;
|
|
1170
|
-
if (idx >= items.length) return;
|
|
1171
|
-
const item = items[idx];
|
|
1172
|
-
if (item !== void 0) await fn(item);
|
|
1173
|
-
}
|
|
1174
|
-
});
|
|
1175
|
-
await Promise.all(workers);
|
|
1176
|
-
}
|
|
1177
1265
|
var SPOOL_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1178
1266
|
var SPOOL_WRITE_HWM_BYTES = 4 * 1024 * 1024;
|
|
1179
1267
|
var sweepStarted = false;
|
|
@@ -1215,7 +1303,7 @@ function createOutputSpool(opts) {
|
|
|
1215
1303
|
let filePath = null;
|
|
1216
1304
|
let failed = false;
|
|
1217
1305
|
let finalized = false;
|
|
1218
|
-
const
|
|
1306
|
+
const open2 = () => {
|
|
1219
1307
|
if (stream || failed) return;
|
|
1220
1308
|
try {
|
|
1221
1309
|
const dir = toolOutputDir();
|
|
@@ -1248,7 +1336,7 @@ function createOutputSpool(opts) {
|
|
|
1248
1336
|
return;
|
|
1249
1337
|
}
|
|
1250
1338
|
head += text;
|
|
1251
|
-
|
|
1339
|
+
open2();
|
|
1252
1340
|
head = "";
|
|
1253
1341
|
return;
|
|
1254
1342
|
}
|
|
@@ -4161,13 +4249,13 @@ ${formatTaskList(taskFile.tasks)}`
|
|
|
4161
4249
|
}
|
|
4162
4250
|
};
|
|
4163
4251
|
function mkResult(plan, ok, message, todos) {
|
|
4164
|
-
const
|
|
4252
|
+
const open2 = plan.items.filter((i) => i.status !== "done").length;
|
|
4165
4253
|
const result = {
|
|
4166
4254
|
ok,
|
|
4167
4255
|
message,
|
|
4168
4256
|
plan: formatPlan(plan),
|
|
4169
4257
|
count: plan.items.length,
|
|
4170
|
-
open
|
|
4258
|
+
open: open2
|
|
4171
4259
|
};
|
|
4172
4260
|
if (todos !== void 0) result.todos = todos;
|
|
4173
4261
|
return result;
|
|
@@ -8039,6 +8127,8 @@ var IndexStore = class {
|
|
|
8039
8127
|
this.db.exec("CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)");
|
|
8040
8128
|
this.db.exec("CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)");
|
|
8041
8129
|
this.db.exec("CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)");
|
|
8130
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)");
|
|
8131
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)");
|
|
8042
8132
|
this.db.exec(`
|
|
8043
8133
|
CREATE TABLE IF NOT EXISTS refs (
|
|
8044
8134
|
id INTEGER PRIMARY KEY,
|
|
@@ -8951,9 +9041,9 @@ async function syncGoParse(filePath, content, lang) {
|
|
|
8951
9041
|
}
|
|
8952
9042
|
}
|
|
8953
9043
|
async function parseSymbols3(opts) {
|
|
8954
|
-
const { file, lang } = opts;
|
|
9044
|
+
const { file, content, lang } = opts;
|
|
8955
9045
|
try {
|
|
8956
|
-
return await syncPyParse(file, lang);
|
|
9046
|
+
return await syncPyParse(file, content, lang);
|
|
8957
9047
|
} catch {
|
|
8958
9048
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
8959
9049
|
}
|
|
@@ -9021,8 +9111,7 @@ syms = []
|
|
|
9021
9111
|
errors = []
|
|
9022
9112
|
|
|
9023
9113
|
try:
|
|
9024
|
-
|
|
9025
|
-
source = f.read()
|
|
9114
|
+
source = sys.stdin.read()
|
|
9026
9115
|
tree = ast.parse(source, filename=sys.argv[1])
|
|
9027
9116
|
except Exception as e:
|
|
9028
9117
|
errors.append(str(e))
|
|
@@ -9162,16 +9251,21 @@ visitor.visit(tree)
|
|
|
9162
9251
|
|
|
9163
9252
|
print(json.dumps([s.to_dict() for s in syms]))
|
|
9164
9253
|
`;
|
|
9165
|
-
|
|
9254
|
+
var _cachedScriptPath = null;
|
|
9255
|
+
async function syncPyParse(filePath, content, lang) {
|
|
9166
9256
|
try {
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9257
|
+
if (!_cachedScriptPath) {
|
|
9258
|
+
const tmpDir = path.join(os2.tmpdir(), "ws-py-parse");
|
|
9259
|
+
await fs7.mkdir(tmpDir, { recursive: true });
|
|
9260
|
+
_cachedScriptPath = path.join(tmpDir, "parse.py");
|
|
9261
|
+
await fs7.writeFile(_cachedScriptPath, PY_PARSE_SCRIPT, "utf8");
|
|
9262
|
+
}
|
|
9263
|
+
const proc = spawn("python", [_cachedScriptPath, filePath], {
|
|
9172
9264
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9173
9265
|
windowsHide: true
|
|
9174
9266
|
});
|
|
9267
|
+
proc.stdin?.write(content);
|
|
9268
|
+
proc.stdin?.end();
|
|
9175
9269
|
let stdout = "";
|
|
9176
9270
|
proc.stdout?.on("data", (chunk) => {
|
|
9177
9271
|
stdout += chunk.toString();
|
|
@@ -9838,7 +9932,7 @@ async function parseFile(file, content, lang) {
|
|
|
9838
9932
|
case "go":
|
|
9839
9933
|
return parseSymbols2({ file, content, lang: "go" });
|
|
9840
9934
|
case "py":
|
|
9841
|
-
return parseSymbols3({ file, lang: "py" });
|
|
9935
|
+
return parseSymbols3({ file, content, lang: "py" });
|
|
9842
9936
|
case "rs":
|
|
9843
9937
|
return parseSymbols4({ file, content, lang: "rs" });
|
|
9844
9938
|
case "json":
|
|
@@ -9869,10 +9963,12 @@ async function runIndexerWithStore(store, opts) {
|
|
|
9869
9963
|
let symbolsIndexed = 0;
|
|
9870
9964
|
const isGitIgnored = await loadGitignoreMatcher(projectRoot);
|
|
9871
9965
|
let files;
|
|
9966
|
+
let discoveredFiles = null;
|
|
9872
9967
|
if (opts.files && opts.files.length > 0) {
|
|
9873
9968
|
files = opts.files.map((f) => path.resolve(projectRoot, f)).filter((f) => !isGitIgnored(path.relative(projectRoot, f).replace(/\\/g, "/"), false));
|
|
9874
9969
|
} else {
|
|
9875
9970
|
files = await findSourceFiles(projectRoot, ignore, isGitIgnored, signal);
|
|
9971
|
+
discoveredFiles = new Set(files);
|
|
9876
9972
|
}
|
|
9877
9973
|
if (langs && langs.length > 0) {
|
|
9878
9974
|
const langSet = new Set(langs);
|
|
@@ -9990,11 +10086,11 @@ async function runIndexerWithStore(store, opts) {
|
|
|
9990
10086
|
filesIndexed++;
|
|
9991
10087
|
}
|
|
9992
10088
|
}
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
10089
|
+
if (discoveredFiles) {
|
|
10090
|
+
for (const [file_] of existingMeta) {
|
|
10091
|
+
if (!discoveredFiles.has(file_)) {
|
|
10092
|
+
store.deleteFile(file_);
|
|
10093
|
+
}
|
|
9998
10094
|
}
|
|
9999
10095
|
}
|
|
10000
10096
|
const durationMs = Date.now() - startMs;
|