@nanhara/hara 0.132.3 → 0.132.4

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/CHANGELOG.md CHANGED
@@ -5,15 +5,26 @@ All notable changes to `@nanhara/hara`.
5
5
  > Versioning (pre-1.0, SemVer-style): the **minor** (middle) number bumps for a **new feature**; the
6
6
  > **patch** (last) number bumps for **optimizations/fixes of existing features**.
7
7
 
8
- ## 0.132.3 — 2026-07-22 — immediate prompt-key routing and verified release carrier
8
+ ## 0.132.4 — 2026-07-22 — release-class Intel readiness handshakes
9
+
10
+ - Non-Git `@path` completion now skips the bounded Git inventory subprocess when no repository marker
11
+ exists. Slow or contended machines keep the full synchronous budget for the actual filesystem walk instead
12
+ of occasionally returning an empty completion list.
13
+ - TUI streaming and semantic-cancellation regressions now synchronize on concrete composer, render, provider,
14
+ and completion handshakes rather than fixed millisecond sleeps. Main-branch CI also runs the complete suite
15
+ on the same Intel macOS class used for native releases before any immutable version tag is created.
16
+ - This patch carries the complete 0.132 feature set into the native and Desktop release train. Upgrade with
17
+ `npm i -g @nanhara/hara@0.132.4`.
18
+
19
+ ## 0.132.3 — 2026-07-22 — immediate prompt-key routing (npm published; native assets withheld)
9
20
 
10
21
  - TUI approval/select input now reads the live visible prompt and selection through stable refs. A key pressed
11
22
  immediately after the prompt paints can no longer hit the previous render's null-prompt closure and be
12
23
  swallowed; rapid arrow-plus-Enter input also uses the current selection before the next paint.
13
24
  - The confirmation regression waits for the visible prompt and then presses `y` without an arbitrary grace
14
25
  delay, covering the Node 24 CI failure directly. Remaining process-tree fixtures also wait for valid PID
15
- content rather than file creation alone. This patch carries the complete 0.132 feature set into the native
16
- and Desktop release train. Upgrade with `npm i -g @nanhara/hara@0.132.3`.
26
+ content rather than file creation alone. The npm package is valid, but native assembly was withheld after
27
+ the release-class Intel lane exposed additional completion/render fixture races; upgrade to 0.132.4 instead.
17
28
 
18
29
  ## 0.132.2 — 2026-07-22 — complete bounded native release gates (npm published; native assets withheld)
19
30
 
package/dist/fs-walk.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Shared filesystem walker — powers @file completion and the grep/glob tools.
2
2
  // Walks a directory tree, skipping noise dirs, capped so huge trees stay responsive.
3
- import { readdirSync, statSync } from "node:fs";
3
+ import { lstatSync, readdirSync, realpathSync, statSync } from "node:fs";
4
4
  import { opendir } from "node:fs/promises";
5
- import { join, relative, sep } from "node:path";
5
+ import { dirname, join, relative, resolve, sep } from "node:path";
6
6
  import { execFile, execSync } from "node:child_process";
7
7
  import { fuzzyRank } from "./fuzzy.js";
8
8
  import { isSensitiveFilePath } from "./security/sensitive-files.js";
@@ -22,6 +22,37 @@ const DEFAULT_ASYNC_TIMEOUT_MS = 2_000;
22
22
  // interruptible. Keep them on a much tighter wall budget; agent/tool paths use the async APIs below.
23
23
  const DEFAULT_SYNC_TIMEOUT_MS = 250;
24
24
  const DEFAULT_YIELD_EVERY = 128;
25
+ function gitMarkerOnPath(start) {
26
+ let dir = resolve(start);
27
+ for (let depth = 0; depth < 128; depth++) {
28
+ try {
29
+ lstatSync(join(dir, ".git"));
30
+ return true;
31
+ }
32
+ catch (error) {
33
+ // An unreadable or otherwise suspicious marker must still take the Git path. Only a definite
34
+ // absence permits the filesystem fallback to skip spawning Git.
35
+ if (error?.code !== "ENOENT")
36
+ return true;
37
+ }
38
+ const parent = dirname(dir);
39
+ if (parent === dir)
40
+ return false;
41
+ dir = parent;
42
+ }
43
+ return true;
44
+ }
45
+ function gitMarkerAbove(start) {
46
+ if (gitMarkerOnPath(start))
47
+ return true;
48
+ // Preserve worktree semantics when callers reach a repository through a symlinked project path.
49
+ try {
50
+ return gitMarkerOnPath(realpathSync.native(start));
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
25
56
  function finiteLimit(value, fallback) {
26
57
  return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
27
58
  }
@@ -228,6 +259,12 @@ export function listProjectFiles(root, cap = 8000) {
228
259
  if (recursiveRootContainsHome(root))
229
260
  return [];
230
261
  const startedAt = Date.now();
262
+ // On a non-repository directory, a contended `git ls-files` can consume the entire synchronous
263
+ // completion budget before the real filesystem walk starts. A bounded marker scan is sufficient to
264
+ // prove that Git cannot be authoritative here, leaving the budget for the user's actual files.
265
+ if (!gitMarkerAbove(root)) {
266
+ return walkFiles(root, cap, { timeoutMs: Math.max(0, DEFAULT_SYNC_TIMEOUT_MS - (Date.now() - startedAt)) });
267
+ }
231
268
  try {
232
269
  const out = execSync("git ls-files --cached --others --exclude-standard", {
233
270
  cwd: root,
@@ -288,6 +325,19 @@ export async function listProjectFilesAsync(root, options = {}) {
288
325
  if (cfg.maxEntries === 0)
289
326
  return result([], 0, 0, "entry_limit");
290
327
  const remaining = () => cfg.timeoutMs - (Date.now() - startedAt);
328
+ if (!gitMarkerAbove(root)) {
329
+ const timeoutMs = remaining();
330
+ if (timeoutMs <= 0)
331
+ return result([], 0, 0, "time_limit");
332
+ return walkFilesAsync(root, {
333
+ maxFiles: cfg.maxFiles,
334
+ maxDirectories: cfg.maxDirectories,
335
+ maxEntries: cfg.maxEntries,
336
+ timeoutMs,
337
+ signal: cfg.signal,
338
+ yieldEvery: cfg.yieldEvery,
339
+ });
340
+ }
291
341
  try {
292
342
  if (remaining() <= 0)
293
343
  return result([], 0, 0, "time_limit");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanhara/hara",
3
- "version": "0.132.3",
3
+ "version": "0.132.4",
4
4
  "description": "hara — a coding agent CLI that runs like an engineering org.",
5
5
  "bin": {
6
6
  "hara": "runtime-bootstrap.cjs"