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.
- package/package.json +1 -1
- package/tui/hud.tsx +26 -7
package/package.json
CHANGED
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
|
|
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
|
|
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
|
-
|
|
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 === 'ㅂ')
|
|
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) {
|