claude-code-hud 0.3.9 → 0.3.11

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/package.json +1 -1
  2. package/tui/hud.tsx +26 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-hud",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "description": "Terminal HUD for Claude Code — real-time token usage, git status, project monitor",
5
5
  "type": "module",
6
6
  "bin": {
package/tui/hud.tsx CHANGED
@@ -3,7 +3,7 @@
3
3
  * HUD Live — Ink TUI
4
4
  * Run: npm run hud (from hud-plugin root)
5
5
  */
6
- import React, { useState, useEffect, useCallback } from 'react';
6
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
7
7
  import { render, Box, Text, useStdout, useInput } from 'ink';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { dirname, join, basename } from 'path';
@@ -95,13 +95,13 @@ type ProjectInfo = {
95
95
  dirTree: DirNode;
96
96
  };
97
97
 
98
- async function scanProject(cwd: string): Promise<ProjectInfo> {
98
+ async function scanProject(cwd: string, deep = 8): Promise<ProjectInfo> {
99
99
  const { default: fg } = await import('fast-glob');
100
100
 
101
101
  // File counts by extension
102
102
  const files: string[] = (await fg('**/*', {
103
103
  cwd, ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**', '**/__pycache__/**', '**/target/**', '**/.next/**', '**/.nuxt/**'],
104
- onlyFiles: true, dot: false, deep: 8,
104
+ onlyFiles: true, dot: false, deep,
105
105
  })).slice(0, 3000);
106
106
 
107
107
  const byExt: Record<string, number> = {};
@@ -155,7 +155,7 @@ async function scanProject(cwd: string): Promise<ProjectInfo> {
155
155
 
156
156
  // Endpoint detection
157
157
  const srcFiles: string[] = await fg('**/*.{ts,tsx,js,jsx,py,java,go}', {
158
- cwd, ignore: ['**/node_modules/**', '**/.git/**', '**/*.test.*', '**/*.spec.*'], onlyFiles: true, deep: 8,
158
+ cwd, ignore: ['**/node_modules/**', '**/.git/**', '**/*.test.*', '**/*.spec.*'], onlyFiles: true, deep,
159
159
  });
160
160
  const endpoints: Record<string, number> = { GET: 0, POST: 0, PUT: 0, DELETE: 0, PATCH: 0 };
161
161
  const PATTERNS: [string, RegExp][] = [
@@ -601,6 +601,13 @@ function ProjectTab({ info, treeCursor, treeExpanded, selectedFile, fileLines, f
601
601
 
602
602
  // ── Tab 3: GIT ─────────────────────────────────────────────────────────────
603
603
  function GitTab({ git, C, termWidth, branchMode, branchList, branchCursor }: any) {
604
+ if (!git.isRepo) return (
605
+ <Box flexDirection="column" borderStyle="single" borderColor={C.border} paddingX={1}>
606
+ <Text color={C.dimmer}>⚠ git repository not found in this directory</Text>
607
+ <Text color={C.dimmer}> cd into a git repo to see branch, diff, and commit info</Text>
608
+ </Box>
609
+ );
610
+
604
611
  const gitFiles = [
605
612
  ...(git.modified ?? []).map((f: string) => ({ status: 'MOD', path: f })),
606
613
  ...(git.added ?? []).map((f: string) => ({ status: 'ADD', path: f })),
@@ -770,6 +777,9 @@ function App() {
770
777
  const [spinFrame, setSpinFrame] = useState(0);
771
778
  const SPIN = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
772
779
 
780
+ // q key debounce ref (require 2 presses within 600ms to quit)
781
+ const lastQRef = useRef(0);
782
+
773
783
  // Branch switcher state
774
784
  const [branchMode, setBranchMode] = useState(false);
775
785
  const [branchList, setBranchList] = useState<string[]>([]);
@@ -797,7 +807,11 @@ function App() {
797
807
 
798
808
  useEffect(() => {
799
809
  // Scan project once
800
- scanProject(cwd).then(p => { setProject(p); setLoading(false); }).catch(() => { setLoading(false); });
810
+ // Quick shallow scan first show UI immediately
811
+ scanProject(cwd, 2).then(p => { setProject(p); setLoading(false); })
812
+ .catch(() => { setLoading(false); });
813
+ // Full deep scan in background → update silently
814
+ scanProject(cwd, 8).then(p => { setProject(p); }).catch(() => {});
801
815
  // Initial API usage fetch
802
816
  getUsage().then(setRateLimits).catch(() => {});
803
817
  // Initial timeline load
@@ -893,7 +907,12 @@ function App() {
893
907
  return;
894
908
  }
895
909
 
896
- if (input === 'q' || input === 'ㅂ') process.exit(0);
910
+ if (input === 'q' || input === 'ㅂ') {
911
+ const now = Date.now();
912
+ if (now - lastQRef.current < 600) { process.exit(0); }
913
+ lastQRef.current = now;
914
+ return;
915
+ }
897
916
 
898
917
  // Escape: close file viewer first, then quit
899
918
  if (key.escape) {
@@ -912,7 +931,7 @@ function App() {
912
931
  refresh();
913
932
  setProject(null);
914
933
  setSelectedFile(null); setFileLines([]); setFileScroll(0);
915
- scanProject(cwd).then(p => { setProject(p); setTreeCursor(0); }).catch(() => {});
934
+ scanProject(cwd, 8).then(p => { setProject(p); setTreeCursor(0); }).catch(() => {});
916
935
  }
917
936
 
918
937
  if (input === 'j' || input === 'ㅓ' || key.downArrow) {