agenthud 0.5.2 → 0.5.4
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 +53 -38
- package/dist/index.js +44 -85
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -3,37 +3,25 @@
|
|
|
3
3
|
Terminal dashboard for AI agent development.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
┌─
|
|
7
|
-
│
|
|
8
|
-
│
|
|
9
|
-
│
|
|
10
|
-
│
|
|
11
|
-
│
|
|
12
|
-
│
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
┌─
|
|
16
|
-
│
|
|
17
|
-
│
|
|
18
|
-
│
|
|
19
|
-
│
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
│
|
|
24
|
-
|
|
25
|
-
│ ✓ Add TestPanel component │
|
|
26
|
-
│ ○ Publish to npm │
|
|
27
|
-
├─ Decisions ──────────────────────────────────────────────┤
|
|
28
|
-
│ • Use dependency injection for git module testing │
|
|
29
|
-
│ • Use Ink for terminal UI │
|
|
30
|
-
│ • Use git log --numstat for stats instead of git diff... │
|
|
31
|
-
└──────────────────────────────────────────────────────────┘
|
|
32
|
-
|
|
33
|
-
┌─ Tests ──────────────────────────────────────────────────┐
|
|
34
|
-
│ ⚠ Outdated (1 commit behind) │
|
|
35
|
-
│ ✓ 70 passed · 3529727 · 40m ago │
|
|
36
|
-
└──────────────────────────────────────────────────────────┘
|
|
6
|
+
┌─ Claude ─────────────────────────────────────────────────────┐
|
|
7
|
+
│ [10:30:00] > User: Show me the project structure │
|
|
8
|
+
│ [10:30:05] * Glob: src/**/*.ts │
|
|
9
|
+
│ [10:30:10] ○ Read: package.json │
|
|
10
|
+
│ [10:30:15] < Response: Here's the project structure... │
|
|
11
|
+
│ [10:30:20] $ Bash: npm run test │
|
|
12
|
+
│ [10:30:25] ~ Edit: src/index.ts │
|
|
13
|
+
└──────────────────────────────────────────────────────────────┘
|
|
14
|
+
|
|
15
|
+
┌─ Git ────────────────────────────────────────────────────────┐
|
|
16
|
+
│ main · +1068 -166 · 12 commits · 23 files │
|
|
17
|
+
│ • 1d00dc0 refactor: rename project from agent-dashboa... │
|
|
18
|
+
│ • 3529727 fix: Decisions separator line width now mat... │
|
|
19
|
+
│ • d7652c4 fix: use proper box character for Decisions... │
|
|
20
|
+
└──────────────────────────────────────────────────────────────┘
|
|
21
|
+
|
|
22
|
+
┌─ Tests ──────────────────────────────────────────────────────┐
|
|
23
|
+
│ ✓ 301 passed · 3fd7988 │
|
|
24
|
+
└──────────────────────────────────────────────────────────────┘
|
|
37
25
|
```
|
|
38
26
|
|
|
39
27
|
## Install
|
|
@@ -43,17 +31,44 @@ npx agenthud
|
|
|
43
31
|
|
|
44
32
|
## Features
|
|
45
33
|
|
|
34
|
+
- **Claude**: Real-time Claude Code session monitoring
|
|
46
35
|
- **Git**: Branch, commits, line changes
|
|
47
|
-
- **Plan**: Progress, decisions from `.agenthud/plan.json`
|
|
48
36
|
- **Tests**: Results with outdated detection
|
|
37
|
+
- **Project**: Package info, stack detection
|
|
38
|
+
|
|
39
|
+
## Claude Panel Icons
|
|
40
|
+
|
|
41
|
+
| Symbol | Type |
|
|
42
|
+
|--------|------|
|
|
43
|
+
| `>` | User input |
|
|
44
|
+
| `<` | Response |
|
|
45
|
+
| `~` | Edit/Write |
|
|
46
|
+
| `○` | Read |
|
|
47
|
+
| `$` | Bash |
|
|
48
|
+
| `*` | Glob/Grep |
|
|
49
|
+
| `@` | Web |
|
|
50
|
+
| `▶` | Task |
|
|
51
|
+
| `?` | Question |
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
49
54
|
|
|
50
|
-
|
|
55
|
+
Create `.agenthud.yaml` in your project root:
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
```yaml
|
|
58
|
+
panels:
|
|
59
|
+
git:
|
|
60
|
+
enabled: true
|
|
61
|
+
interval: 30s
|
|
62
|
+
claude:
|
|
63
|
+
enabled: true
|
|
64
|
+
interval: 5s
|
|
65
|
+
max_activities: 20
|
|
66
|
+
tests:
|
|
67
|
+
enabled: true
|
|
68
|
+
interval: manual
|
|
69
|
+
project:
|
|
70
|
+
enabled: true
|
|
71
|
+
interval: 60s
|
|
57
72
|
```
|
|
58
73
|
|
|
59
74
|
## Keyboard
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { Box as Box7, Text as Text7, useApp, useInput, useStdout } from "ink";
|
|
|
13
13
|
import { Box, Text } from "ink";
|
|
14
14
|
|
|
15
15
|
// src/ui/constants.ts
|
|
16
|
+
import stringWidth from "string-width";
|
|
16
17
|
var DEFAULT_PANEL_WIDTH = 70;
|
|
17
18
|
var MIN_TERMINAL_WIDTH = 50;
|
|
18
19
|
var MAX_TERMINAL_WIDTH = 120;
|
|
@@ -57,35 +58,7 @@ function truncate(text, maxLength) {
|
|
|
57
58
|
if (text.length <= maxLength) return text;
|
|
58
59
|
return text.slice(0, maxLength - 3) + "...";
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
let width = 0;
|
|
62
|
-
for (const char of str) {
|
|
63
|
-
const code = char.codePointAt(0) || 0;
|
|
64
|
-
if (code >= 127744 && code <= 129535 || // Misc symbols, emoticons, etc.
|
|
65
|
-
code >= 9728 && code <= 9983 || // Misc symbols
|
|
66
|
-
code >= 9984 && code <= 10175 || // Dingbats (includes ✏)
|
|
67
|
-
code >= 128512 && code <= 128591 || // Emoticons
|
|
68
|
-
code >= 128640 && code <= 128767) {
|
|
69
|
-
width += 2;
|
|
70
|
-
} else if (code === 65039) {
|
|
71
|
-
continue;
|
|
72
|
-
} else if (
|
|
73
|
-
// CJK characters (Korean, Chinese, Japanese) - 2 wide
|
|
74
|
-
code >= 44032 && code <= 55215 || // Korean Hangul syllables
|
|
75
|
-
code >= 4352 && code <= 4607 || // Korean Hangul Jamo
|
|
76
|
-
code >= 12592 && code <= 12687 || // Korean Hangul Compatibility Jamo
|
|
77
|
-
code >= 19968 && code <= 40959 || // CJK Unified Ideographs
|
|
78
|
-
code >= 13312 && code <= 19903 || // CJK Extension A
|
|
79
|
-
code >= 12288 && code <= 12351 || // CJK Symbols
|
|
80
|
-
code >= 65280 && code <= 65519
|
|
81
|
-
) {
|
|
82
|
-
width += 2;
|
|
83
|
-
} else {
|
|
84
|
-
width += 1;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return width;
|
|
88
|
-
}
|
|
61
|
+
var getDisplayWidth = stringWidth;
|
|
89
62
|
|
|
90
63
|
// src/ui/GitPanel.tsx
|
|
91
64
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -520,13 +493,13 @@ function formatActivityParts(activity, maxWidth) {
|
|
|
520
493
|
}
|
|
521
494
|
detailDisplayWidth = currentWidth;
|
|
522
495
|
}
|
|
523
|
-
const
|
|
496
|
+
const labelContent2 = `${label}: ${truncatedDetail}`;
|
|
524
497
|
const displayWidth2 = totalPrefixWidth + detailDisplayWidth;
|
|
525
|
-
return { timestamp,
|
|
498
|
+
return { timestamp, icon, labelContent: labelContent2, displayWidth: displayWidth2 };
|
|
526
499
|
}
|
|
527
|
-
const
|
|
500
|
+
const labelContent = label;
|
|
528
501
|
const displayWidth = totalPrefixWidth;
|
|
529
|
-
return { timestamp,
|
|
502
|
+
return { timestamp, icon, labelContent, displayWidth };
|
|
530
503
|
}
|
|
531
504
|
function ClaudePanel({
|
|
532
505
|
data,
|
|
@@ -588,17 +561,21 @@ function ClaudePanel({
|
|
|
588
561
|
const lines = [];
|
|
589
562
|
for (let i = 0; i < state.activities.length; i++) {
|
|
590
563
|
const activity = state.activities[i];
|
|
591
|
-
const { timestamp,
|
|
564
|
+
const { timestamp, icon, labelContent, displayWidth } = formatActivityParts(activity, contentWidth);
|
|
592
565
|
const padding = Math.max(0, contentWidth - displayWidth);
|
|
593
566
|
const style = getActivityStyle(activity);
|
|
567
|
+
const clearEOL = "\x1B[K";
|
|
594
568
|
lines.push(
|
|
595
569
|
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
596
570
|
BOX.v,
|
|
597
571
|
" ",
|
|
598
572
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: timestamp }),
|
|
599
|
-
/* @__PURE__ */ jsx4(Text4, { color:
|
|
573
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", children: icon }),
|
|
574
|
+
" ",
|
|
575
|
+
/* @__PURE__ */ jsx4(Text4, { color: style.color, dimColor: style.dimColor, children: labelContent }),
|
|
600
576
|
" ".repeat(padding),
|
|
601
|
-
BOX.v
|
|
577
|
+
BOX.v,
|
|
578
|
+
clearEOL
|
|
602
579
|
] }, `activity-${i}`)
|
|
603
580
|
);
|
|
604
581
|
}
|
|
@@ -1331,6 +1308,29 @@ import {
|
|
|
1331
1308
|
} from "fs";
|
|
1332
1309
|
import { homedir } from "os";
|
|
1333
1310
|
import { join as join2, basename as basename2 } from "path";
|
|
1311
|
+
|
|
1312
|
+
// src/types/index.ts
|
|
1313
|
+
var ICONS = {
|
|
1314
|
+
// Activity types
|
|
1315
|
+
User: ">",
|
|
1316
|
+
Response: "<",
|
|
1317
|
+
// Tools
|
|
1318
|
+
Edit: "~",
|
|
1319
|
+
Write: "~",
|
|
1320
|
+
Read: "\u25CB",
|
|
1321
|
+
Bash: "$",
|
|
1322
|
+
Glob: "*",
|
|
1323
|
+
Grep: "*",
|
|
1324
|
+
WebFetch: "@",
|
|
1325
|
+
WebSearch: "@",
|
|
1326
|
+
Task: "\u25B6",
|
|
1327
|
+
TodoWrite: "~",
|
|
1328
|
+
AskUserQuestion: "?",
|
|
1329
|
+
// Fallback
|
|
1330
|
+
Default: "$"
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
// src/data/claude.ts
|
|
1334
1334
|
var fs = {
|
|
1335
1335
|
existsSync: nodeExistsSync2,
|
|
1336
1336
|
readFileSync: (path) => nodeReadFileSync3(path, "utf-8"),
|
|
@@ -1341,20 +1341,6 @@ var FIVE_MINUTES_MS = 5 * 60 * 1e3;
|
|
|
1341
1341
|
var THIRTY_SECONDS_MS = 30 * 1e3;
|
|
1342
1342
|
var MAX_LINES_TO_SCAN = 200;
|
|
1343
1343
|
var DEFAULT_MAX_ACTIVITIES = 10;
|
|
1344
|
-
var MAX_DETAIL_LENGTH = 45;
|
|
1345
|
-
var TOOL_ICONS = {
|
|
1346
|
-
Edit: "\u{1F4DD}",
|
|
1347
|
-
Write: "\u{1F4DD}",
|
|
1348
|
-
Read: "\u{1F4D6}",
|
|
1349
|
-
Bash: "\u{1F527}",
|
|
1350
|
-
Glob: "\u{1F50D}",
|
|
1351
|
-
Grep: "\u{1F50D}",
|
|
1352
|
-
WebFetch: "\u{1F310}",
|
|
1353
|
-
WebSearch: "\u{1F310}",
|
|
1354
|
-
Task: "\u{1F4CB}",
|
|
1355
|
-
TodoWrite: "\u{1F4DD}",
|
|
1356
|
-
AskUserQuestion: "\u2753"
|
|
1357
|
-
};
|
|
1358
1344
|
function getClaudeSessionPath(projectPath) {
|
|
1359
1345
|
const encoded = projectPath.replace(/\//g, "-");
|
|
1360
1346
|
return join2(homedir(), ".claude", "projects", encoded);
|
|
@@ -1384,46 +1370,19 @@ function findActiveSession(sessionDir) {
|
|
|
1384
1370
|
}
|
|
1385
1371
|
return null;
|
|
1386
1372
|
}
|
|
1387
|
-
function getDisplayWidth2(str) {
|
|
1388
|
-
let width = 0;
|
|
1389
|
-
for (const char of str) {
|
|
1390
|
-
const code = char.codePointAt(0) || 0;
|
|
1391
|
-
if (code >= 127744 && code <= 129535 || code >= 9728 && code <= 9983 || code >= 9984 && code <= 10175 || code >= 128512 && code <= 128591 || code >= 128640 && code <= 128767 || code >= 44032 && code <= 55215 || code >= 4352 && code <= 4607 || code >= 12592 && code <= 12687 || code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 12288 && code <= 12351 || code >= 65280 && code <= 65519) {
|
|
1392
|
-
width += 2;
|
|
1393
|
-
} else if (code !== 65039) {
|
|
1394
|
-
width += 1;
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
return width;
|
|
1398
|
-
}
|
|
1399
|
-
function truncate2(str, maxDisplayWidth) {
|
|
1400
|
-
const currentWidth = getDisplayWidth2(str);
|
|
1401
|
-
if (currentWidth <= maxDisplayWidth) return str;
|
|
1402
|
-
let result = "";
|
|
1403
|
-
let width = 0;
|
|
1404
|
-
for (const char of str) {
|
|
1405
|
-
const charWidth = getDisplayWidth2(char);
|
|
1406
|
-
if (width + charWidth > maxDisplayWidth - 3) {
|
|
1407
|
-
return result + "...";
|
|
1408
|
-
}
|
|
1409
|
-
result += char;
|
|
1410
|
-
width += charWidth;
|
|
1411
|
-
}
|
|
1412
|
-
return result;
|
|
1413
|
-
}
|
|
1414
1373
|
function getToolDetail(toolName, input) {
|
|
1415
1374
|
if (!input) return "";
|
|
1416
1375
|
if (input.command) {
|
|
1417
|
-
return
|
|
1376
|
+
return input.command.replace(/\n/g, " ");
|
|
1418
1377
|
}
|
|
1419
1378
|
if (input.file_path) {
|
|
1420
1379
|
return basename2(input.file_path);
|
|
1421
1380
|
}
|
|
1422
1381
|
if (input.pattern) {
|
|
1423
|
-
return
|
|
1382
|
+
return input.pattern;
|
|
1424
1383
|
}
|
|
1425
1384
|
if (input.query) {
|
|
1426
|
-
return
|
|
1385
|
+
return input.query;
|
|
1427
1386
|
}
|
|
1428
1387
|
return "";
|
|
1429
1388
|
}
|
|
@@ -1475,9 +1434,9 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
|
|
|
1475
1434
|
activities.push({
|
|
1476
1435
|
timestamp: lastTimestamp || /* @__PURE__ */ new Date(),
|
|
1477
1436
|
type: "user",
|
|
1478
|
-
icon:
|
|
1437
|
+
icon: ICONS.User,
|
|
1479
1438
|
label: "User",
|
|
1480
|
-
detail:
|
|
1439
|
+
detail: userText.replace(/\n/g, " ")
|
|
1481
1440
|
});
|
|
1482
1441
|
}
|
|
1483
1442
|
lastType = "user";
|
|
@@ -1492,7 +1451,7 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
|
|
|
1492
1451
|
for (const block of messageContent) {
|
|
1493
1452
|
if (block.type === "tool_use") {
|
|
1494
1453
|
const toolName = block.name || "Tool";
|
|
1495
|
-
const icon =
|
|
1454
|
+
const icon = ICONS[toolName] || ICONS.Default;
|
|
1496
1455
|
const detail = getToolDetail(toolName, block.input);
|
|
1497
1456
|
activities.push({
|
|
1498
1457
|
timestamp: lastTimestamp || /* @__PURE__ */ new Date(),
|
|
@@ -1507,9 +1466,9 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
|
|
|
1507
1466
|
activities.push({
|
|
1508
1467
|
timestamp: lastTimestamp || /* @__PURE__ */ new Date(),
|
|
1509
1468
|
type: "response",
|
|
1510
|
-
icon:
|
|
1469
|
+
icon: ICONS.Response,
|
|
1511
1470
|
label: "Response",
|
|
1512
|
-
detail:
|
|
1471
|
+
detail: block.text.replace(/\n/g, " ")
|
|
1513
1472
|
});
|
|
1514
1473
|
lastType = "response";
|
|
1515
1474
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenthud",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
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",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"ink": "^6.6.0",
|
|
54
54
|
"react": "^19.2.3",
|
|
55
|
+
"string-width": "^8.1.0",
|
|
55
56
|
"yaml": "^2.8.2"
|
|
56
57
|
}
|
|
57
58
|
}
|