agenthud 0.5.15 → 0.5.17

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/README.md CHANGED
@@ -12,7 +12,7 @@ When working with AI coding agents like Claude Code, you lose visibility into wh
12
12
 
13
13
  ## Install
14
14
 
15
- Requires Node.js 20+
15
+ Requires Node.js 20+. Tested on Ubuntu, Windows, macOS.
16
16
 
17
17
  ```bash
18
18
  npx agenthud
@@ -67,16 +67,88 @@ panels:
67
67
  interval: 10s
68
68
  ```
69
69
 
70
+ ## Panels
71
+
72
+ ### Claude Panel
73
+
74
+ Shows real-time Claude Code activity:
75
+
76
+ ```
77
+ ┌─ Claude ─────────────────────────────────────────────┐
78
+ │ [10:23:45] ○ Read: src/components/Button.tsx │
79
+ │ [10:23:46] ~ Edit: src/components/Button.tsx │
80
+ │ [10:23:47] $ Bash: npm test │
81
+ │ [10:23:50] < Response: Tests passed successfully... │
82
+ └──────────────────────────────────────────────────────┘
83
+ ```
84
+
85
+ - **○ Read**: File being read
86
+ - **~ Edit/Write**: File being modified
87
+ - **$ Bash**: Command being executed
88
+ - **< Response**: Claude's text response
89
+
90
+ ### Git Panel
91
+
92
+ Shows today's git activity and current state:
93
+
94
+ ```
95
+ ┌─ Git ────────────────────────────────────────────────┐
96
+ │ feat/add-dashboard · +142 -23 · 3 commits · 5 files │
97
+ │ • abc1234 Add dashboard component │
98
+ │ • def5678 Fix styling issues │
99
+ └──────────────────────────────────────────────────────┘
100
+ ```
101
+
102
+ - **Branch name**: Current working branch (green)
103
+ - **Stats**: Lines added/deleted, commits, files changed
104
+ - **dirty**: Shows uncommitted change count (yellow)
105
+
106
+ ### Tests Panel
107
+
108
+ Shows test results with staleness detection:
109
+
110
+ ```
111
+ ┌─ Tests ──────────────────────────────────────────────┐
112
+ │ ✓ 42 passed ✗ 1 failed ○ 2 skipped · abc1234 │
113
+ │ ⚠ Outdated (3 commits behind) │
114
+ │──────────────────────────────────────────────────────│
115
+ │ ✗ Button.test.tsx │
116
+ │ • should render correctly │
117
+ └──────────────────────────────────────────────────────┘
118
+ ```
119
+
120
+ - **✓ passed** (green), **✗ failed** (red), **○ skipped**
121
+ - **⚠ Outdated**: Warning if tests are behind commits
122
+ - **Failures**: Shows failing test file and name
123
+
124
+ ### Project Panel
125
+
126
+ Shows project overview and structure:
127
+
128
+ ```
129
+ ┌─ Project ────────────────────────────────────────────┐
130
+ │ agenthud · TypeScript · MIT │
131
+ │ Stack: react, ink, vitest │
132
+ │ Files: 45 .ts · Lines: 3.2k │
133
+ │ Deps: 12 prod · 8 dev │
134
+ └──────────────────────────────────────────────────────┘
135
+ ```
136
+
137
+ - **Name/Language/License**: Project basics
138
+ - **Stack**: Detected frameworks and tools
139
+ - **Files/Lines**: Source code stats
140
+ - **Deps**: Dependency counts
141
+
70
142
  ### Other Sessions Panel
71
143
 
72
144
  Shows activity from your other Claude Code projects:
73
145
 
74
146
  ```
75
147
  ┌─ Other Sessions ─────────────────────────────────────┐
76
- │ 📁 dotfiles, pain-radar, myapp +4 | ⚡ 1 active
148
+ │ 📁 dotfiles, pain-radar, myapp +4 | ⚡ 1 active
77
149
  │ │
78
- │ 🔵 dotfiles (2m ago)
79
- │ "Updated the config file as requested..."
150
+ │ 🔵 dotfiles (2m ago)
151
+ │ "Updated the config file as requested..."
80
152
  └──────────────────────────────────────────────────────┘
81
153
  ```
82
154
 
package/dist/index.js CHANGED
@@ -956,6 +956,11 @@ function WelcomePanel() {
956
956
  import { execSync as nodeExecSync, exec as nodeExec } from "child_process";
957
957
  import { promisify } from "util";
958
958
  var execAsync = promisify(nodeExec);
959
+ function cleanOutput(str) {
960
+ let result = str.replace(/^\uFEFF/, "");
961
+ result = result.replace(/^"|"$/g, "");
962
+ return result.trim();
963
+ }
959
964
  var execFn = (command, options2) => nodeExecSync(command, options2);
960
965
  function getUncommittedCount() {
961
966
  try {
@@ -1041,11 +1046,12 @@ async function getGitDataAsync(config) {
1041
1046
  let commits = [];
1042
1047
  try {
1043
1048
  const { stdout } = await execAsync(commands.commits);
1044
- const lines = stdout.trim().split("\n").filter(Boolean);
1049
+ const lines = cleanOutput(stdout).split("\n").filter(Boolean);
1045
1050
  commits = lines.map((line) => {
1046
- const [hash, timestamp, ...messageParts] = line.split("|");
1051
+ const cleanLine = cleanOutput(line);
1052
+ const [hash, timestamp, ...messageParts] = cleanLine.split("|");
1047
1053
  return {
1048
- hash,
1054
+ hash: cleanOutput(hash),
1049
1055
  message: messageParts.join("|"),
1050
1056
  timestamp: new Date(timestamp)
1051
1057
  };
@@ -1905,10 +1911,11 @@ function getOtherSessionsData(currentProjectPath, options2 = {}) {
1905
1911
  }
1906
1912
  const allProjects = getAllProjects();
1907
1913
  defaultResult.totalProjects = allProjects.length;
1908
- const normalizedCurrentPath = currentProjectPath.replace(/\/$/, "");
1914
+ const normalizedCurrentPath = currentProjectPath.replace(/[/\\]$/, "").replace(/\\/g, "/");
1909
1915
  const otherSessions = [];
1910
1916
  for (const project of allProjects) {
1911
- if (project.decodedPath === normalizedCurrentPath) {
1917
+ const normalizedDecodedPath = project.decodedPath.replace(/\\/g, "/");
1918
+ if (normalizedDecodedPath === normalizedCurrentPath) {
1912
1919
  continue;
1913
1920
  }
1914
1921
  const projectDir = join3(projectsDir, project.encodedPath);
@@ -2509,22 +2516,31 @@ function DashboardApp({ mode }) {
2509
2516
  const { exit } = useApp();
2510
2517
  const { stdout } = useStdout();
2511
2518
  const { config, warnings } = useMemo(() => parseConfig(), []);
2512
- const [width, setWidth] = useState(() => getClampedWidth(stdout?.columns));
2519
+ const getEffectiveWidth = (terminalColumns) => {
2520
+ if (config.width) {
2521
+ return config.width;
2522
+ }
2523
+ return getClampedWidth(terminalColumns);
2524
+ };
2525
+ const [width, setWidth] = useState(() => getEffectiveWidth(stdout?.columns));
2513
2526
  useEffect(() => {
2514
- const newWidth = getClampedWidth(stdout?.columns);
2515
- if (newWidth !== width) {
2516
- setWidth(newWidth);
2527
+ if (!config.width) {
2528
+ const newWidth = getEffectiveWidth(stdout?.columns);
2529
+ if (newWidth !== width) {
2530
+ setWidth(newWidth);
2531
+ }
2517
2532
  }
2518
- }, [stdout?.columns, width]);
2533
+ }, [stdout?.columns, width, config.width]);
2519
2534
  useEffect(() => {
2535
+ if (config.width) return;
2520
2536
  const handleResize = () => {
2521
- setWidth(getClampedWidth(stdout?.columns));
2537
+ setWidth(getEffectiveWidth(stdout?.columns));
2522
2538
  };
2523
2539
  stdout?.on("resize", handleResize);
2524
2540
  return () => {
2525
2541
  stdout?.off("resize", handleResize);
2526
2542
  };
2527
- }, [stdout]);
2543
+ }, [stdout, config.width]);
2528
2544
  const projectIntervalSeconds = config.panels.project.interval ? config.panels.project.interval / 1e3 : null;
2529
2545
  const gitIntervalSeconds = config.panels.git.interval ? config.panels.git.interval / 1e3 : null;
2530
2546
  const claudeIntervalSeconds = config.panels.claude.interval ? config.panels.claude.interval / 1e3 : null;
@@ -1,4 +1,7 @@
1
1
  # agenthud configuration
2
+
3
+ width: 100 # between 50~120
4
+
2
5
  panels:
3
6
  claude:
4
7
  enabled: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenthud",
3
- "version": "0.5.15",
3
+ "version": "0.5.17",
4
4
  "description": "CLI tool to monitor agent status in real-time. Works with Claude Code, multi-agent workflows, and any AI agent system.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",