agenthud 0.6.4 → 0.6.5

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/dist/index.js +143 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -602,6 +602,68 @@ function getToolDetail(_toolName, input) {
602
602
  }
603
603
  return "";
604
604
  }
605
+ var MAX_SUB_ACTIVITIES = 3;
606
+ function getSubagentFiles(sessionFile) {
607
+ const subagentsDir = join3(sessionFile.replace(/\.jsonl$/, ""), "subagents");
608
+ if (!existsSync4(subagentsDir)) {
609
+ return [];
610
+ }
611
+ try {
612
+ const files = readdirSync(subagentsDir).filter(
613
+ (f) => f.endsWith(".jsonl")
614
+ );
615
+ const fileInfos = files.map((file) => {
616
+ const filePath = join3(subagentsDir, file);
617
+ const stat = statSync(filePath);
618
+ return { filePath, mtimeMs: stat.mtimeMs };
619
+ });
620
+ fileInfos.sort((a, b) => b.mtimeMs - a.mtimeMs);
621
+ return fileInfos;
622
+ } catch {
623
+ return [];
624
+ }
625
+ }
626
+ function parseSubagentFile(filePath) {
627
+ try {
628
+ const content = readFileSync5(filePath, "utf-8");
629
+ const lines = content.trim().split("\n").filter(Boolean);
630
+ const allActivities = [];
631
+ for (const line of lines) {
632
+ try {
633
+ const entry = JSON.parse(line);
634
+ if (entry.type === "assistant" && entry.message?.content) {
635
+ const messageContent = entry.message.content;
636
+ if (Array.isArray(messageContent)) {
637
+ for (const block of messageContent) {
638
+ if (block.type === "tool_use" && block.name) {
639
+ const toolName = block.name;
640
+ if (toolName === "TodoWrite") continue;
641
+ const icon = ICONS[toolName] || ICONS.Default;
642
+ const detail = getToolDetail(toolName, block.input);
643
+ const timestamp = entry.timestamp ? new Date(entry.timestamp) : /* @__PURE__ */ new Date();
644
+ allActivities.push({
645
+ timestamp,
646
+ type: "tool",
647
+ icon,
648
+ label: toolName,
649
+ detail
650
+ });
651
+ }
652
+ }
653
+ }
654
+ }
655
+ } catch {
656
+ }
657
+ }
658
+ allActivities.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
659
+ return {
660
+ activities: allActivities.slice(0, MAX_SUB_ACTIVITIES),
661
+ totalCount: allActivities.length
662
+ };
663
+ } catch {
664
+ return { activities: [], totalCount: 0 };
665
+ }
666
+ }
605
667
  function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES) {
606
668
  const defaultState = {
607
669
  status: "none",
@@ -699,13 +761,14 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
699
761
  lastActivity.count = (lastActivity.count || 1) + 1;
700
762
  lastActivity.timestamp = lastTimestamp || /* @__PURE__ */ new Date();
701
763
  } else {
702
- activities.push({
764
+ const activity = {
703
765
  timestamp: lastTimestamp || /* @__PURE__ */ new Date(),
704
766
  type: "tool",
705
767
  icon,
706
768
  label: toolName,
707
769
  detail
708
- });
770
+ };
771
+ activities.push(activity);
709
772
  }
710
773
  lastType = "tool";
711
774
  } else if (block.type === "text" && block.text) {
@@ -755,10 +818,10 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
755
818
  const subagentsDir = join3(sessionFile.replace(/\.jsonl$/, ""), "subagents");
756
819
  if (existsSync4(subagentsDir)) {
757
820
  try {
758
- const subagentFiles = readdirSync(subagentsDir).filter(
821
+ const subagentFiles2 = readdirSync(subagentsDir).filter(
759
822
  (f) => f.endsWith(".jsonl")
760
823
  );
761
- for (const file of subagentFiles) {
824
+ for (const file of subagentFiles2) {
762
825
  const filePath = join3(subagentsDir, file);
763
826
  try {
764
827
  const subContent = readFileSync5(filePath, "utf-8");
@@ -779,9 +842,22 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
779
842
  } catch {
780
843
  }
781
844
  }
845
+ const finalActivities = activities.slice(-maxActivities).reverse();
846
+ const subagentFiles = getSubagentFiles(sessionFile);
847
+ let taskIndex = 0;
848
+ for (const activity of finalActivities) {
849
+ if (activity.label === "Task" && taskIndex < subagentFiles.length) {
850
+ const subagentData = parseSubagentFile(subagentFiles[taskIndex].filePath);
851
+ if (subagentData.totalCount > 0) {
852
+ activity.subActivities = subagentData.activities;
853
+ activity.subActivityCount = subagentData.totalCount;
854
+ }
855
+ taskIndex++;
856
+ }
857
+ }
782
858
  return {
783
859
  status,
784
- activities: activities.slice(-maxActivities).reverse(),
860
+ activities: finalActivities,
785
861
  tokenCount,
786
862
  sessionStartTime,
787
863
  todos
@@ -2111,8 +2187,15 @@ function ClaudePanel({
2111
2187
  const lines = [];
2112
2188
  for (let i = 0; i < state.activities.length; i++) {
2113
2189
  const activity = state.activities[i];
2190
+ let modifiedActivity = activity;
2191
+ if (activity.label === "Task" && activity.subActivityCount && activity.subActivityCount > 0) {
2192
+ modifiedActivity = {
2193
+ ...activity,
2194
+ detail: activity.detail ? `${activity.detail} (${activity.subActivityCount})` : `(${activity.subActivityCount})`
2195
+ };
2196
+ }
2114
2197
  const { timestamp, icon, labelContent, displayWidth } = formatActivityParts(
2115
- activity,
2198
+ modifiedActivity,
2116
2199
  contentWidth
2117
2200
  );
2118
2201
  const padding = Math.max(0, contentWidth - displayWidth);
@@ -2131,6 +2214,60 @@ function ClaudePanel({
2131
2214
  clearEOL
2132
2215
  ] }, `activity-${i}`)
2133
2216
  );
2217
+ if (activity.subActivities && activity.subActivities.length > 0) {
2218
+ const subPrefix = " \u2514 ";
2219
+ const subPrefixWidth = getDisplayWidth(subPrefix);
2220
+ for (let j = 0; j < activity.subActivities.length; j++) {
2221
+ const sub = activity.subActivities[j];
2222
+ const subStyle = getActivityStyle(sub);
2223
+ const subIcon = sub.icon;
2224
+ const subIconWidth = getDisplayWidth(subIcon);
2225
+ const subLabel = sub.label;
2226
+ const subDetail = sub.detail;
2227
+ const subContentPrefixWidth = subPrefixWidth + subIconWidth + 1;
2228
+ const availableWidth = contentWidth - subContentPrefixWidth;
2229
+ let subLabelContent;
2230
+ let subDisplayWidth;
2231
+ if (subDetail) {
2232
+ const labelPart = `${subLabel}: `;
2233
+ const detailAvailable = availableWidth - labelPart.length;
2234
+ let truncatedDetail = subDetail;
2235
+ if (getDisplayWidth(subDetail) > detailAvailable) {
2236
+ truncatedDetail = "";
2237
+ let currentWidth = 0;
2238
+ for (const char of subDetail) {
2239
+ const charWidth = getDisplayWidth(char);
2240
+ if (currentWidth + charWidth > detailAvailable - 3) {
2241
+ truncatedDetail += "...";
2242
+ currentWidth += 3;
2243
+ break;
2244
+ }
2245
+ truncatedDetail += char;
2246
+ currentWidth += charWidth;
2247
+ }
2248
+ }
2249
+ subLabelContent = labelPart + truncatedDetail;
2250
+ subDisplayWidth = subContentPrefixWidth + labelPart.length + getDisplayWidth(truncatedDetail);
2251
+ } else {
2252
+ subLabelContent = subLabel;
2253
+ subDisplayWidth = subContentPrefixWidth + subLabel.length;
2254
+ }
2255
+ const subPadding = Math.max(0, contentWidth - subDisplayWidth);
2256
+ lines.push(
2257
+ /* @__PURE__ */ jsxs(Text, { children: [
2258
+ BOX.v,
2259
+ " ",
2260
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: subPrefix }),
2261
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: subIcon }),
2262
+ " ",
2263
+ /* @__PURE__ */ jsx(Text, { color: subStyle.color, dimColor: subStyle.dimColor, children: subLabelContent }),
2264
+ " ".repeat(subPadding),
2265
+ BOX.v,
2266
+ clearEOL
2267
+ ] }, `activity-${i}-sub-${j}`)
2268
+ );
2269
+ }
2270
+ }
2134
2271
  }
2135
2272
  const hasTodos = state.todos && state.todos.length > 0;
2136
2273
  const allCompleted = hasTodos && state.todos?.every((t) => t.status === "completed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenthud",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
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",