@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.
Files changed (2) hide show
  1. package/dist/index.js +30 -4
  2. 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
- const walk = (dir, depth) => {
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 readdirSync(dir, { withFileTypes: true })) {
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",
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.3"
24
+ "@vincemakes/kiso-core": "0.16.5"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^26.1.2",