agenthud 0.5.14 → 0.5.16

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
@@ -26,6 +26,7 @@ Run this in a separate terminal while using Claude Code.
26
26
  - **Track your git state** - Commits, branches, uncommitted changes at a glance
27
27
  - **Know if tests pass** - Results update automatically, shows if outdated
28
28
  - **Stay oriented** - Project info, dependencies, file counts
29
+ - **Monitor other sessions** - See what's happening in your other Claude Code projects
29
30
 
30
31
  ## Usage
31
32
 
@@ -61,8 +62,28 @@ panels:
61
62
  project:
62
63
  enabled: true
63
64
  interval: 60s
65
+ other_sessions:
66
+ enabled: true
67
+ interval: 10s
64
68
  ```
65
69
 
70
+ ### Other Sessions Panel
71
+
72
+ Shows activity from your other Claude Code projects:
73
+
74
+ ```
75
+ ┌─ Other Sessions ─────────────────────────────────────┐
76
+ │ 📁 dotfiles, pain-radar, myapp +4 | ⚡ 1 active │
77
+ │ │
78
+ │ 🔵 dotfiles (2m ago) │
79
+ │ "Updated the config file as requested..." │
80
+ └──────────────────────────────────────────────────────┘
81
+ ```
82
+
83
+ - **Project names**: Shows up to 3 recent projects, +N for more
84
+ - **Active indicator**: 🔵 active (within 5 min), ⚪ inactive
85
+ - **Last message**: Most recent assistant response from that session
86
+
66
87
  ## Keyboard
67
88
 
68
89
  - `q` quit
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
  };
@@ -1509,7 +1515,7 @@ var THIRTY_SECONDS_MS = 30 * 1e3;
1509
1515
  var MAX_LINES_TO_SCAN = 200;
1510
1516
  var DEFAULT_MAX_ACTIVITIES = 10;
1511
1517
  function getClaudeSessionPath(projectPath) {
1512
- const encoded = projectPath.replace(/\//g, "-");
1518
+ const encoded = projectPath.replace(/[/\\]/g, "-");
1513
1519
  return join2(homedir(), ".claude", "projects", encoded);
1514
1520
  }
1515
1521
  function findActiveSession(sessionDir) {
@@ -1735,7 +1741,7 @@ import {
1735
1741
  statSync as nodeStatSync2
1736
1742
  } from "fs";
1737
1743
  import { homedir as homedir2 } from "os";
1738
- import { join as join3, basename as basename3 } from "path";
1744
+ import { join as join3, basename as basename3, sep } from "path";
1739
1745
  var fs2 = {
1740
1746
  existsSync: nodeExistsSync3,
1741
1747
  readFileSync: (path) => nodeReadFileSync4(path, "utf-8"),
@@ -1748,7 +1754,7 @@ function getProjectsDir() {
1748
1754
  return join3(homedir2(), ".claude", "projects");
1749
1755
  }
1750
1756
  function decodeProjectPath(encoded) {
1751
- const naiveDecoded = encoded.replace(/-/g, "/");
1757
+ const naiveDecoded = encoded.replace(/-/g, sep);
1752
1758
  if (fs2.existsSync(naiveDecoded)) {
1753
1759
  return naiveDecoded;
1754
1760
  }
@@ -1762,7 +1768,7 @@ function decodeProjectPath(encoded) {
1762
1768
  let found = false;
1763
1769
  for (let j = segments.length; j > i; j--) {
1764
1770
  const segment = segments.slice(i, j).join("-");
1765
- const testPath = currentPath + "/" + segment;
1771
+ const testPath = currentPath ? join3(currentPath, segment) : sep + segment;
1766
1772
  try {
1767
1773
  if (fs2.existsSync(testPath)) {
1768
1774
  const stat = fs2.statSync(testPath);
@@ -1777,7 +1783,7 @@ function decodeProjectPath(encoded) {
1777
1783
  }
1778
1784
  }
1779
1785
  if (!found) {
1780
- currentPath += "/" + segments[i];
1786
+ currentPath = currentPath ? join3(currentPath, segments[i]) : sep + segments[i];
1781
1787
  i++;
1782
1788
  }
1783
1789
  }
@@ -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;
@@ -3035,7 +3051,7 @@ function getDefaultConfig2() {
3035
3051
  return nodeReadFileSync7(templatePath, "utf-8");
3036
3052
  }
3037
3053
  function getClaudeSessionPath2(projectPath) {
3038
- const encoded = projectPath.replace(/\//g, "-");
3054
+ const encoded = projectPath.replace(/[/\\]/g, "-");
3039
3055
  return join5(homedir3(), ".claude", "projects", encoded);
3040
3056
  }
3041
3057
  function runInit(cwd = process.cwd()) {
@@ -1,4 +1,7 @@
1
1
  # agenthud configuration
2
+
3
+ width: 80 # 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.14",
3
+ "version": "0.5.16",
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",