@vincemakes/kiso-tools-node 0.16.3 → 0.16.5
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/index.js +30 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { execFileSync, spawn } from "node:child_process";
|
|
21
21
|
import { chmodSync, existsSync, linkSync, readdirSync, readFileSync, realpathSync, renameSync, statSync, appendFileSync, mkdirSync, rmSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
22
|
+
import { readdir } from "node:fs/promises";
|
|
22
23
|
import { createHash } from "node:crypto";
|
|
23
24
|
import { tmpdir } from "node:os";
|
|
24
25
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -72,6 +73,10 @@ const DEFAULT_SHELL_TIMEOUT_MS = 30_000;
|
|
|
72
73
|
// red line: every truncation names its continuation — the model always
|
|
73
74
|
// has a path to the full content.
|
|
74
75
|
const DEFAULT_READ_LINES = 200;
|
|
76
|
+
/** R3: how many files a search may read before it hands the event loop
|
|
77
|
+
* back. Small enough that the 200ms motion cadence never misses a beat,
|
|
78
|
+
* large enough that the yield costs nothing on a small tree. */
|
|
79
|
+
const YIELD_EVERY = 64;
|
|
75
80
|
const MAX_SEARCH_MATCHES = 50;
|
|
76
81
|
const MAX_DIR_ENTRIES = 200;
|
|
77
82
|
function cap(text) {
|
|
@@ -411,17 +416,38 @@ export function searchTextTool(opts) {
|
|
|
411
416
|
// depth cap and the node_modules/dotfile skip stay.
|
|
412
417
|
const matches = [];
|
|
413
418
|
let totalMatches = 0;
|
|
414
|
-
|
|
419
|
+
// R3 — the walk YIELDS. It was `readdirSync` + `readFileSync` all
|
|
420
|
+
// the way down inside an `async` body, which is the shape that
|
|
421
|
+
// blocks Node's event loop for the whole traversal: measured at
|
|
422
|
+
// 18.4 seconds over a home directory, during which no timer
|
|
423
|
+
// fires, no frame paints and the `working` mark freezes solid.
|
|
424
|
+
// A user reasonably reads a frozen liveness mark as a crash.
|
|
425
|
+
//
|
|
426
|
+
// The fix is not "make it faster" — a big tree is legitimately
|
|
427
|
+
// slow. It is to stop OWNING the loop: `fs.promises.readdir`,
|
|
428
|
+
// and a yield every YIELD_EVERY files so a long read stretch
|
|
429
|
+
// cannot monopolise it either. Same traversal, same order, same
|
|
430
|
+
// caps, same results; only the loop is shared now.
|
|
431
|
+
let sinceYield = 0;
|
|
432
|
+
const breathe = async () => {
|
|
433
|
+
sinceYield += 1;
|
|
434
|
+
if (sinceYield < YIELD_EVERY)
|
|
435
|
+
return;
|
|
436
|
+
sinceYield = 0;
|
|
437
|
+
await new Promise((r) => setImmediate(r));
|
|
438
|
+
};
|
|
439
|
+
const walk = async (dir, depth) => {
|
|
415
440
|
if (depth > 8)
|
|
416
441
|
return;
|
|
417
|
-
for (const entry of
|
|
442
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
418
443
|
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
419
444
|
continue;
|
|
420
445
|
const full = join(dir, entry.name);
|
|
421
446
|
if (entry.isDirectory()) {
|
|
422
|
-
walk(full, depth + 1);
|
|
447
|
+
await walk(full, depth + 1);
|
|
423
448
|
}
|
|
424
449
|
else if (entry.isFile()) {
|
|
450
|
+
await breathe();
|
|
425
451
|
try {
|
|
426
452
|
// round 8: same inode boundary as read_file — a hard link
|
|
427
453
|
// to an external inode is not searched. round 4 (adversarial):
|
|
@@ -448,7 +474,7 @@ export function searchTextTool(opts) {
|
|
|
448
474
|
}
|
|
449
475
|
};
|
|
450
476
|
try {
|
|
451
|
-
walk(root, 0);
|
|
477
|
+
await walk(root, 0);
|
|
452
478
|
}
|
|
453
479
|
catch (err) {
|
|
454
480
|
return { content: `search_text failed: ${err.message}`, isError: true, errorKind: "fatal" };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tools-node",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.5",
|
|
4
4
|
"description": "kiso coding tools for Node hosts — read file, list directory, search text, write/edit file, shell command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "vitest run"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@vincemakes/kiso-core": "0.16.
|
|
24
|
+
"@vincemakes/kiso-core": "0.16.5"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^26.1.2",
|