claude-code-hud 0.3.11 → 0.3.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-hud",
3
- "version": "0.3.11",
3
+ "version": "0.3.12",
4
4
  "description": "Terminal HUD for Claude Code — real-time token usage, git status, project monitor",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,39 +1,44 @@
1
1
  /**
2
- * Git status via child_process. No external deps.
2
+ * Git status via child_process exec (async — non-blocking).
3
3
  */
4
- import { execSync } from 'child_process';
4
+ import { exec } from 'child_process';
5
+ import { promisify } from 'util';
5
6
 
6
- function run(cmd, cwd) {
7
+ const execAsync = promisify(exec);
8
+
9
+ async function run(cmd, cwd) {
7
10
  try {
8
- return execSync(cmd, { cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
11
+ const { stdout } = await execAsync(cmd, { cwd, timeout: 3000 });
12
+ return stdout.trim();
9
13
  } catch {
10
14
  return '';
11
15
  }
12
16
  }
13
17
 
14
- export function readGitInfo(cwd = process.cwd()) {
15
- const branch = run('git rev-parse --abbrev-ref HEAD', cwd) || 'unknown';
18
+ export async function readGitInfo(cwd = process.cwd()) {
19
+ const branch = await run('git rev-parse --abbrev-ref HEAD', cwd) || 'unknown';
16
20
  if (branch === 'unknown' || branch === 'HEAD') {
17
21
  return { isRepo: false, branch: 'unknown', ahead: 0, behind: 0, modified: [], added: [], deleted: [], recentCommits: [], totalChanges: 0 };
18
22
  }
19
23
 
20
- // ahead/behind
21
- const aheadBehind = run('git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null || echo "0\t0"', cwd);
24
+ const [aheadBehind, statusOut, logOut, numstatOut] = await Promise.all([
25
+ run('git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null || echo "0\t0"', cwd),
26
+ run('git status --porcelain', cwd),
27
+ run('git log --oneline -5 --format="%h|%s|%cr"', cwd),
28
+ run('git diff --numstat HEAD 2>/dev/null', cwd),
29
+ ]);
30
+
22
31
  const [behind = 0, ahead = 0] = aheadBehind.split('\t').map(Number);
23
32
 
24
- // status
25
- const statusOut = run('git status --porcelain', cwd);
26
33
  const modified = [], added = [], deleted = [];
27
34
  for (const line of statusOut.split('\n').filter(Boolean)) {
28
35
  const st = line.slice(0, 2).trim();
29
36
  const file = line.slice(2).trimStart();
30
37
  if (st === 'M' || st === 'MM' || st === 'AM') modified.push(file);
31
- else if (st === 'A' || st === '??' ) added.push(file);
38
+ else if (st === 'A' || st === '??') added.push(file);
32
39
  else if (st === 'D') deleted.push(file);
33
40
  }
34
41
 
35
- // recent commits
36
- const logOut = run('git log --oneline -5 --format="%h|%s|%cr"', cwd);
37
42
  const recentCommits = logOut.split('\n').filter(Boolean).map(l => {
38
43
  const [hash, ...rest] = l.split('|');
39
44
  const time = rest.pop();
@@ -41,8 +46,6 @@ export function readGitInfo(cwd = process.cwd()) {
41
46
  return { hash, msg, time };
42
47
  });
43
48
 
44
- // diff stats: actual +/- line counts per file
45
- const numstatOut = run('git diff --numstat HEAD 2>/dev/null', cwd);
46
49
  const diffStats = {};
47
50
  for (const line of numstatOut.split('\n').filter(Boolean)) {
48
51
  const [addStr, delStr, ...fileParts] = line.split('\t');
package/tui/hud.tsx CHANGED
@@ -753,7 +753,7 @@ function App() {
753
753
 
754
754
  const [usage, setUsage] = useState<any>(readTokenUsage(cwd));
755
755
  const [history, setHistory] = useState<any>(readTokenHistory(cwd));
756
- const [git, setGit] = useState<any>(readGitInfo(cwd));
756
+ const [git, setGit] = useState<any>({ isRepo: false, branch: 'loading…', modified: [], added: [], deleted: [], recentCommits: [], totalChanges: 0 });
757
757
  const [project, setProject] = useState<ProjectInfo | null>(null);
758
758
  const [rateLimits, setRateLimits] = useState<any>(getUsageSync());
759
759
 
@@ -793,8 +793,8 @@ function App() {
793
793
  const refresh = useCallback(() => {
794
794
  setUsage(readTokenUsage(cwd));
795
795
  setHistory(readTokenHistory(cwd));
796
- setGit(readGitInfo(cwd));
797
796
  setUpdatedAt(Date.now());
797
+ readGitInfo(cwd).then(setGit).catch(() => {});
798
798
  getUsage().then(setRateLimits).catch(() => {});
799
799
  readSessionTimeline(cwd).then(entries => {
800
800
  setTimeline(entries);
@@ -812,6 +812,8 @@ function App() {
812
812
  .catch(() => { setLoading(false); });
813
813
  // Full deep scan in background → update silently
814
814
  scanProject(cwd, 8).then(p => { setProject(p); }).catch(() => {});
815
+ // Initial git load (async)
816
+ readGitInfo(cwd).then(setGit).catch(() => {});
815
817
  // Initial API usage fetch
816
818
  getUsage().then(setRateLimits).catch(() => {});
817
819
  // Initial timeline load