agenthud 0.6.4 → 0.7.0

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 +366 -135
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -355,7 +355,9 @@ function getDefaultConfig2() {
355
355
  }
356
356
  },
357
357
  panelOrder: ["project", "git", "tests", "claude", "other_sessions"],
358
- width: DEFAULT_WIDTH
358
+ width: DEFAULT_WIDTH,
359
+ wideLayoutThreshold: null
360
+ // disabled by default
359
361
  };
360
362
  }
361
363
  var BUILTIN_PANELS = ["project", "git", "tests", "claude", "other_sessions"];
@@ -410,6 +412,18 @@ function parseConfig() {
410
412
  config.width = parsed.width;
411
413
  }
412
414
  }
415
+ const MIN_WIDE_THRESHOLD = 140;
416
+ const wideThresholdValue = parsed.wideLayoutThreshold ?? parsed.wide_layout_threshold;
417
+ if (typeof wideThresholdValue === "number") {
418
+ if (wideThresholdValue < MIN_WIDE_THRESHOLD) {
419
+ warnings.push(
420
+ `wideLayoutThreshold ${wideThresholdValue} is too small, using minimum of ${MIN_WIDE_THRESHOLD}`
421
+ );
422
+ config.wideLayoutThreshold = MIN_WIDE_THRESHOLD;
423
+ } else {
424
+ config.wideLayoutThreshold = wideThresholdValue;
425
+ }
426
+ }
413
427
  const panels = parsed.panels;
414
428
  if (!panels || typeof panels !== "object") {
415
429
  return { config, warnings };
@@ -550,6 +564,9 @@ var ICONS = {
550
564
  };
551
565
 
552
566
  // src/data/claude.ts
567
+ function stripAnsi(text) {
568
+ return text.replace(/\x1b\[[0-9;]*m/g, "");
569
+ }
553
570
  var MAX_LINES_TO_SCAN = 200;
554
571
  var DEFAULT_MAX_ACTIVITIES = 10;
555
572
  function getClaudeSessionPath2(projectPath) {
@@ -586,22 +603,84 @@ function findActiveSession(sessionDir, sessionTimeout) {
586
603
  function getToolDetail(_toolName, input) {
587
604
  if (!input) return "";
588
605
  if (input.command) {
589
- return input.command.replace(/\n/g, " ");
606
+ return stripAnsi(input.command.replace(/\n/g, " "));
590
607
  }
591
608
  if (input.file_path) {
592
609
  return basename(input.file_path);
593
610
  }
594
611
  if (input.pattern) {
595
- return input.pattern;
612
+ return stripAnsi(input.pattern);
596
613
  }
597
614
  if (input.query) {
598
- return input.query;
615
+ return stripAnsi(input.query);
599
616
  }
600
617
  if (input.description) {
601
- return input.description;
618
+ return stripAnsi(input.description);
602
619
  }
603
620
  return "";
604
621
  }
622
+ var MAX_SUB_ACTIVITIES = 3;
623
+ function getSubagentFiles(sessionFile) {
624
+ const subagentsDir = join3(sessionFile.replace(/\.jsonl$/, ""), "subagents");
625
+ if (!existsSync4(subagentsDir)) {
626
+ return [];
627
+ }
628
+ try {
629
+ const files = readdirSync(subagentsDir).filter(
630
+ (f) => f.endsWith(".jsonl")
631
+ );
632
+ const fileInfos = files.map((file) => {
633
+ const filePath = join3(subagentsDir, file);
634
+ const stat = statSync(filePath);
635
+ return { filePath, mtimeMs: stat.mtimeMs };
636
+ });
637
+ fileInfos.sort((a, b) => b.mtimeMs - a.mtimeMs);
638
+ return fileInfos;
639
+ } catch {
640
+ return [];
641
+ }
642
+ }
643
+ function parseSubagentFile(filePath) {
644
+ try {
645
+ const content = readFileSync5(filePath, "utf-8");
646
+ const lines = content.trim().split("\n").filter(Boolean);
647
+ const allActivities = [];
648
+ for (const line of lines) {
649
+ try {
650
+ const entry = JSON.parse(line);
651
+ if (entry.type === "assistant" && entry.message?.content) {
652
+ const messageContent = entry.message.content;
653
+ if (Array.isArray(messageContent)) {
654
+ for (const block of messageContent) {
655
+ if (block.type === "tool_use" && block.name) {
656
+ const toolName = block.name;
657
+ if (toolName === "TodoWrite") continue;
658
+ const icon = ICONS[toolName] || ICONS.Default;
659
+ const detail = getToolDetail(toolName, block.input);
660
+ const timestamp = entry.timestamp ? new Date(entry.timestamp) : /* @__PURE__ */ new Date();
661
+ allActivities.push({
662
+ timestamp,
663
+ type: "tool",
664
+ icon,
665
+ label: toolName,
666
+ detail
667
+ });
668
+ }
669
+ }
670
+ }
671
+ }
672
+ } catch {
673
+ }
674
+ }
675
+ allActivities.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
676
+ return {
677
+ activities: allActivities.slice(0, MAX_SUB_ACTIVITIES),
678
+ totalCount: allActivities.length
679
+ };
680
+ } catch {
681
+ return { activities: [], totalCount: 0 };
682
+ }
683
+ }
605
684
  function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES) {
606
685
  const defaultState = {
607
686
  status: "none",
@@ -699,13 +778,14 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
699
778
  lastActivity.count = (lastActivity.count || 1) + 1;
700
779
  lastActivity.timestamp = lastTimestamp || /* @__PURE__ */ new Date();
701
780
  } else {
702
- activities.push({
781
+ const activity = {
703
782
  timestamp: lastTimestamp || /* @__PURE__ */ new Date(),
704
783
  type: "tool",
705
784
  icon,
706
785
  label: toolName,
707
786
  detail
708
- });
787
+ };
788
+ activities.push(activity);
709
789
  }
710
790
  lastType = "tool";
711
791
  } else if (block.type === "text" && block.text) {
@@ -755,10 +835,10 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
755
835
  const subagentsDir = join3(sessionFile.replace(/\.jsonl$/, ""), "subagents");
756
836
  if (existsSync4(subagentsDir)) {
757
837
  try {
758
- const subagentFiles = readdirSync(subagentsDir).filter(
838
+ const subagentFiles2 = readdirSync(subagentsDir).filter(
759
839
  (f) => f.endsWith(".jsonl")
760
840
  );
761
- for (const file of subagentFiles) {
841
+ for (const file of subagentFiles2) {
762
842
  const filePath = join3(subagentsDir, file);
763
843
  try {
764
844
  const subContent = readFileSync5(filePath, "utf-8");
@@ -779,9 +859,22 @@ function parseSessionState(sessionFile, maxActivities = DEFAULT_MAX_ACTIVITIES)
779
859
  } catch {
780
860
  }
781
861
  }
862
+ const finalActivities = activities.slice(-maxActivities).reverse();
863
+ const subagentFiles = getSubagentFiles(sessionFile);
864
+ let taskIndex = 0;
865
+ for (const activity of finalActivities) {
866
+ if (activity.label === "Task" && taskIndex < subagentFiles.length) {
867
+ const subagentData = parseSubagentFile(subagentFiles[taskIndex].filePath);
868
+ if (subagentData.totalCount > 0) {
869
+ activity.subActivities = subagentData.activities;
870
+ activity.subActivityCount = subagentData.totalCount;
871
+ }
872
+ taskIndex++;
873
+ }
874
+ }
782
875
  return {
783
876
  status,
784
- activities: activities.slice(-maxActivities).reverse(),
877
+ activities: finalActivities,
785
878
  tokenCount,
786
879
  sessionStartTime,
787
880
  todos
@@ -2050,7 +2143,8 @@ function ClaudePanel({
2050
2143
  countdown,
2051
2144
  width = DEFAULT_PANEL_WIDTH,
2052
2145
  isRunning = false,
2053
- justRefreshed = false
2146
+ justRefreshed = false,
2147
+ maxActivities
2054
2148
  }) {
2055
2149
  const countdownSuffix = isRunning ? "running..." : formatCountdown(countdown);
2056
2150
  const innerWidth = getInnerWidth(width);
@@ -2109,15 +2203,22 @@ function ClaudePanel({
2109
2203
  ] });
2110
2204
  }
2111
2205
  const lines = [];
2112
- for (let i = 0; i < state.activities.length; i++) {
2113
- const activity = state.activities[i];
2206
+ const displayActivities = maxActivities !== void 0 ? state.activities.slice(0, maxActivities) : state.activities;
2207
+ for (let i = 0; i < displayActivities.length; i++) {
2208
+ const activity = displayActivities[i];
2209
+ let modifiedActivity = activity;
2210
+ if (activity.label === "Task" && activity.subActivityCount && activity.subActivityCount > 0) {
2211
+ modifiedActivity = {
2212
+ ...activity,
2213
+ detail: activity.detail ? `${activity.detail} (${activity.subActivityCount})` : `(${activity.subActivityCount})`
2214
+ };
2215
+ }
2114
2216
  const { timestamp, icon, labelContent, displayWidth } = formatActivityParts(
2115
- activity,
2217
+ modifiedActivity,
2116
2218
  contentWidth
2117
2219
  );
2118
2220
  const padding = Math.max(0, contentWidth - displayWidth);
2119
2221
  const style = getActivityStyle(activity);
2120
- const clearEOL = "\x1B[K";
2121
2222
  lines.push(
2122
2223
  /* @__PURE__ */ jsxs(Text, { children: [
2123
2224
  BOX.v,
@@ -2127,10 +2228,62 @@ function ClaudePanel({
2127
2228
  " ",
2128
2229
  /* @__PURE__ */ jsx(Text, { color: style.color, dimColor: style.dimColor, children: labelContent }),
2129
2230
  " ".repeat(padding),
2130
- BOX.v,
2131
- clearEOL
2231
+ BOX.v
2132
2232
  ] }, `activity-${i}`)
2133
2233
  );
2234
+ if (activity.subActivities && activity.subActivities.length > 0) {
2235
+ const subPrefix = " \u2514 ";
2236
+ const subPrefixWidth = getDisplayWidth(subPrefix);
2237
+ for (let j = 0; j < activity.subActivities.length; j++) {
2238
+ const sub = activity.subActivities[j];
2239
+ const subStyle = getActivityStyle(sub);
2240
+ const subIcon = sub.icon;
2241
+ const subIconWidth = getDisplayWidth(subIcon);
2242
+ const subLabel = sub.label;
2243
+ const subDetail = sub.detail;
2244
+ const subContentPrefixWidth = subPrefixWidth + subIconWidth + 1;
2245
+ const availableWidth = contentWidth - subContentPrefixWidth;
2246
+ let subLabelContent;
2247
+ let subDisplayWidth;
2248
+ if (subDetail) {
2249
+ const labelPart = `${subLabel}: `;
2250
+ const detailAvailable = availableWidth - labelPart.length;
2251
+ let truncatedDetail = subDetail;
2252
+ if (getDisplayWidth(subDetail) > detailAvailable) {
2253
+ truncatedDetail = "";
2254
+ let currentWidth = 0;
2255
+ for (const char of subDetail) {
2256
+ const charWidth = getDisplayWidth(char);
2257
+ if (currentWidth + charWidth > detailAvailable - 3) {
2258
+ truncatedDetail += "...";
2259
+ currentWidth += 3;
2260
+ break;
2261
+ }
2262
+ truncatedDetail += char;
2263
+ currentWidth += charWidth;
2264
+ }
2265
+ }
2266
+ subLabelContent = labelPart + truncatedDetail;
2267
+ subDisplayWidth = subContentPrefixWidth + labelPart.length + getDisplayWidth(truncatedDetail);
2268
+ } else {
2269
+ subLabelContent = subLabel;
2270
+ subDisplayWidth = subContentPrefixWidth + subLabel.length;
2271
+ }
2272
+ const subPadding = Math.max(0, contentWidth - subDisplayWidth);
2273
+ lines.push(
2274
+ /* @__PURE__ */ jsxs(Text, { children: [
2275
+ BOX.v,
2276
+ " ",
2277
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: subPrefix }),
2278
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: subIcon }),
2279
+ " ",
2280
+ /* @__PURE__ */ jsx(Text, { color: subStyle.color, dimColor: subStyle.dimColor, children: subLabelContent }),
2281
+ " ".repeat(subPadding),
2282
+ BOX.v
2283
+ ] }, `activity-${i}-sub-${j}`)
2284
+ );
2285
+ }
2286
+ }
2134
2287
  }
2135
2288
  const hasTodos = state.todos && state.todos.length > 0;
2136
2289
  const allCompleted = hasTodos && state.todos?.every((t) => t.status === "completed");
@@ -3217,6 +3370,18 @@ function DashboardApp({
3217
3370
  },
3218
3371
  [config.width]
3219
3372
  );
3373
+ const getEffectiveMaxActivities = useCallback4(
3374
+ (terminalRows, todoCount = 0, isWideLayout = false) => {
3375
+ const configMax = config.panels.claude.maxActivities ?? 10;
3376
+ if (!terminalRows || !isWideLayout) {
3377
+ return configMax;
3378
+ }
3379
+ const todoHeight = todoCount > 0 ? 1 + todoCount : 0;
3380
+ const heightBasedMax = Math.max(5, terminalRows - 13 - todoHeight);
3381
+ return Math.max(configMax, heightBasedMax);
3382
+ },
3383
+ [config.panels.claude.maxActivities]
3384
+ );
3220
3385
  const [width, setWidth] = useState4(() => getEffectiveWidth(stdout?.columns));
3221
3386
  useEffect4(() => {
3222
3387
  if (!config.width) {
@@ -3276,12 +3441,12 @@ function DashboardApp({
3276
3441
  const [gitData, setGitData] = useState4(
3277
3442
  () => getGitData(config.panels.git)
3278
3443
  );
3444
+ const fetchMaxActivities = Math.max(
3445
+ config.panels.claude.maxActivities ?? 10,
3446
+ stdout?.rows ?? 50
3447
+ );
3279
3448
  const [claudeData, setClaudeData] = useState4(
3280
- () => getClaudeData(
3281
- cwd,
3282
- config.panels.claude.maxActivities,
3283
- config.panels.claude.sessionTimeout
3284
- )
3449
+ () => getClaudeData(cwd, fetchMaxActivities, config.panels.claude.sessionTimeout)
3285
3450
  );
3286
3451
  const [otherSessionsData, setOtherSessionsData] = useState4(
3287
3452
  () => getOtherSessionsData(cwd, {
@@ -3294,7 +3459,6 @@ function DashboardApp({
3294
3459
  }
3295
3460
  return getTestData();
3296
3461
  }, [config.panels.tests.command]);
3297
- const [testsDisabled, setTestsDisabled] = useState4(false);
3298
3462
  const [testData, setTestData] = useState4({
3299
3463
  results: null,
3300
3464
  isOutdated: false,
@@ -3305,14 +3469,10 @@ function DashboardApp({
3305
3469
  if (testsInitializedRef.current) return;
3306
3470
  testsInitializedRef.current = true;
3307
3471
  const timer = setTimeout(() => {
3308
- const data = getTestDataFromConfig();
3309
- setTestData(data);
3310
- if (data.error && !config.panels.tests.command) {
3311
- setTestsDisabled(true);
3312
- }
3472
+ setTestData(getTestDataFromConfig());
3313
3473
  }, 0);
3314
3474
  return () => clearTimeout(timer);
3315
- }, [getTestDataFromConfig, config.panels.tests.command]);
3475
+ }, [getTestDataFromConfig]);
3316
3476
  const [customPanelData, setCustomPanelData] = useState4(() => {
3317
3477
  const data = {};
3318
3478
  if (config.customPanels) {
@@ -3344,30 +3504,27 @@ function DashboardApp({
3344
3504
  try {
3345
3505
  await new Promise((resolve) => {
3346
3506
  setTimeout(() => {
3347
- const data = getTestDataFromConfig();
3348
- if (config.panels.tests.command) {
3349
- setTestsDisabled(!!data.error);
3350
- }
3351
- setTestData(data);
3507
+ setTestData(getTestDataFromConfig());
3352
3508
  resolve();
3353
3509
  }, 0);
3354
3510
  });
3355
3511
  } finally {
3356
3512
  visualFeedback.endAsync("tests", { completed: true });
3357
3513
  }
3358
- }, [getTestDataFromConfig, config.panels.tests.command, visualFeedback]);
3514
+ }, [getTestDataFromConfig, visualFeedback]);
3359
3515
  const refreshClaude = useCallback4(() => {
3516
+ const maxFetch = Math.max(
3517
+ config.panels.claude.maxActivities ?? 10,
3518
+ stdout?.rows ?? 50
3519
+ );
3360
3520
  setClaudeData(
3361
- getClaudeData(
3362
- cwd,
3363
- config.panels.claude.maxActivities,
3364
- config.panels.claude.sessionTimeout
3365
- )
3521
+ getClaudeData(cwd, maxFetch, config.panels.claude.sessionTimeout)
3366
3522
  );
3367
3523
  visualFeedback.setRefreshed("claude");
3368
3524
  resetCountdown("claude");
3369
3525
  }, [
3370
3526
  cwd,
3527
+ stdout?.rows,
3371
3528
  config.panels.claude.maxActivities,
3372
3529
  config.panels.claude.sessionTimeout,
3373
3530
  visualFeedback,
@@ -3528,106 +3685,180 @@ function DashboardApp({
3528
3685
  }
3529
3686
  return () => timers.forEach((t) => clearInterval(t));
3530
3687
  }, [isWatchMode, config]);
3688
+ const terminalWidth = stdout?.columns ?? 0;
3689
+ const terminalHeight = stdout?.rows ?? 0;
3690
+ const columnGap = 2;
3691
+ const effectiveThreshold = config.wideLayoutThreshold ?? MIN_TERMINAL_WIDTH * 2 + columnGap;
3692
+ const useWideLayout = terminalWidth >= effectiveThreshold;
3693
+ const singleColumnWidth = getClampedWidth(terminalWidth);
3694
+ const leftColumnWidth = useWideLayout ? Math.floor((terminalWidth - columnGap) / 2) : singleColumnWidth;
3695
+ const rightColumnWidth = useWideLayout ? terminalWidth - leftColumnWidth - columnGap : singleColumnWidth;
3696
+ const claudeMaxActivities = useMemo3(() => {
3697
+ if (!useWideLayout) return void 0;
3698
+ const todos = claudeData.state.todos;
3699
+ const hasTodos = todos && todos.length > 0;
3700
+ const allCompleted = hasTodos && todos.every((t) => t.status === "completed");
3701
+ const activeTodoCount = hasTodos && !allCompleted ? todos.length : 0;
3702
+ return getEffectiveMaxActivities(terminalHeight, activeTodoCount, true);
3703
+ }, [
3704
+ useWideLayout,
3705
+ claudeData.state.todos,
3706
+ terminalHeight,
3707
+ getEffectiveMaxActivities
3708
+ ]);
3709
+ const renderPanel = (panelName, panelWidth, marginTop) => {
3710
+ if (panelName === "project" && config.panels.project.enabled) {
3711
+ const vs = visualFeedback.getState("project");
3712
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3713
+ ProjectPanel,
3714
+ {
3715
+ data: projectData,
3716
+ countdown: isWatchMode ? countdowns.project : null,
3717
+ width: panelWidth,
3718
+ justRefreshed: vs.justRefreshed
3719
+ }
3720
+ ) }, `panel-${panelName}`);
3721
+ }
3722
+ if (panelName === "git" && config.panels.git.enabled) {
3723
+ const vs = visualFeedback.getState("git");
3724
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3725
+ GitPanel,
3726
+ {
3727
+ branch: gitData.branch,
3728
+ commits: gitData.commits,
3729
+ stats: gitData.stats,
3730
+ uncommitted: gitData.uncommitted,
3731
+ countdown: isWatchMode ? countdowns.git : null,
3732
+ width: panelWidth,
3733
+ isRunning: vs.isRunning,
3734
+ justRefreshed: vs.justRefreshed
3735
+ }
3736
+ ) }, `panel-${panelName}`);
3737
+ }
3738
+ if (panelName === "tests" && config.panels.tests.enabled) {
3739
+ const vs = visualFeedback.getState("tests");
3740
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3741
+ TestPanel,
3742
+ {
3743
+ results: testData.results,
3744
+ isOutdated: testData.isOutdated,
3745
+ commitsBehind: testData.commitsBehind,
3746
+ error: testData.error,
3747
+ width: panelWidth,
3748
+ isRunning: vs.isRunning,
3749
+ justCompleted: vs.justCompleted
3750
+ }
3751
+ ) }, `panel-${panelName}`);
3752
+ }
3753
+ if (panelName === "claude" && config.panels.claude.enabled) {
3754
+ const vs = visualFeedback.getState("claude");
3755
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3756
+ ClaudePanel,
3757
+ {
3758
+ data: claudeData,
3759
+ countdown: isWatchMode ? countdowns.claude : null,
3760
+ width: panelWidth,
3761
+ justRefreshed: vs.justRefreshed,
3762
+ maxActivities: claudeMaxActivities
3763
+ }
3764
+ ) }, `panel-${panelName}`);
3765
+ }
3766
+ if (panelName === "other_sessions" && config.panels.other_sessions.enabled) {
3767
+ const vs = visualFeedback.getState("other_sessions");
3768
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3769
+ OtherSessionsPanel,
3770
+ {
3771
+ data: otherSessionsData,
3772
+ countdown: isWatchMode ? countdowns.other_sessions : null,
3773
+ width: panelWidth,
3774
+ isRunning: vs.isRunning,
3775
+ messageMaxLength: config.panels.other_sessions.messageMaxLength
3776
+ }
3777
+ ) }, `panel-${panelName}`);
3778
+ }
3779
+ const customConfig = config.customPanels?.[panelName];
3780
+ if (customConfig?.enabled) {
3781
+ const result = customPanelData[panelName];
3782
+ if (!result) return null;
3783
+ const vs = visualFeedback.getState(panelName);
3784
+ const isManual = customConfig.interval === null;
3785
+ const relativeTime = isManual ? formatRelativeTime3(result.timestamp) : void 0;
3786
+ const countdown = !isManual && isWatchMode ? countdowns[panelName] : null;
3787
+ return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3788
+ GenericPanel,
3789
+ {
3790
+ data: result.data,
3791
+ renderer: customConfig.renderer,
3792
+ countdown,
3793
+ relativeTime,
3794
+ error: result.error,
3795
+ width: panelWidth,
3796
+ isRunning: vs.isRunning,
3797
+ justRefreshed: vs.justRefreshed
3798
+ }
3799
+ ) }, `panel-${panelName}`);
3800
+ }
3801
+ return null;
3802
+ };
3803
+ if (useWideLayout) {
3804
+ const leftPanels = ["claude", "other_sessions"];
3805
+ const rightPanels = config.panelOrder.filter(
3806
+ (name) => !leftPanels.includes(name)
3807
+ );
3808
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
3809
+ warnings.length > 0 && /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
3810
+ "\u26A0 ",
3811
+ warnings.join(", ")
3812
+ ] }) }),
3813
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
3814
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: leftColumnWidth, children: [
3815
+ renderPanel("claude", leftColumnWidth, 0),
3816
+ renderPanel("other_sessions", leftColumnWidth, 1)
3817
+ ] }),
3818
+ /* @__PURE__ */ jsx8(
3819
+ Box8,
3820
+ {
3821
+ flexDirection: "column",
3822
+ width: rightColumnWidth,
3823
+ marginLeft: columnGap,
3824
+ children: rightPanels.map(
3825
+ (panelName, index) => renderPanel(panelName, rightColumnWidth, index === 0 ? 0 : 1)
3826
+ )
3827
+ }
3828
+ )
3829
+ ] }),
3830
+ isWatchMode && /* @__PURE__ */ jsxs8(
3831
+ Box8,
3832
+ {
3833
+ marginTop: 1,
3834
+ width: terminalWidth,
3835
+ justifyContent: "space-between",
3836
+ children: [
3837
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: statusBarItems.map((item, index) => /* @__PURE__ */ jsxs8(React.Fragment, { children: [
3838
+ index > 0 && " \xB7 ",
3839
+ /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
3840
+ item.split(":")[0],
3841
+ ":"
3842
+ ] }),
3843
+ item.split(":").slice(1).join(":")
3844
+ ] }, index)) }),
3845
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
3846
+ "AgentHUD v",
3847
+ getVersion()
3848
+ ] })
3849
+ ]
3850
+ }
3851
+ )
3852
+ ] });
3853
+ }
3531
3854
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
3532
3855
  warnings.length > 0 && /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
3533
3856
  "\u26A0 ",
3534
3857
  warnings.join(", ")
3535
3858
  ] }) }),
3536
- config.panelOrder.map((panelName, index) => {
3537
- const isFirst = index === 0;
3538
- const marginTop = isFirst ? 0 : 1;
3539
- if (panelName === "project" && config.panels.project.enabled) {
3540
- const vs = visualFeedback.getState("project");
3541
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3542
- ProjectPanel,
3543
- {
3544
- data: projectData,
3545
- countdown: isWatchMode ? countdowns.project : null,
3546
- width,
3547
- justRefreshed: vs.justRefreshed
3548
- }
3549
- ) }, `panel-${panelName}-${index}`);
3550
- }
3551
- if (panelName === "git" && config.panels.git.enabled) {
3552
- const vs = visualFeedback.getState("git");
3553
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3554
- GitPanel,
3555
- {
3556
- branch: gitData.branch,
3557
- commits: gitData.commits,
3558
- stats: gitData.stats,
3559
- uncommitted: gitData.uncommitted,
3560
- countdown: isWatchMode ? countdowns.git : null,
3561
- width,
3562
- isRunning: vs.isRunning,
3563
- justRefreshed: vs.justRefreshed
3564
- }
3565
- ) }, `panel-${panelName}-${index}`);
3566
- }
3567
- if (panelName === "tests" && config.panels.tests.enabled && !testsDisabled) {
3568
- const vs = visualFeedback.getState("tests");
3569
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3570
- TestPanel,
3571
- {
3572
- results: testData.results,
3573
- isOutdated: testData.isOutdated,
3574
- commitsBehind: testData.commitsBehind,
3575
- error: testData.error,
3576
- width,
3577
- isRunning: vs.isRunning,
3578
- justCompleted: vs.justCompleted
3579
- }
3580
- ) }, `panel-${panelName}-${index}`);
3581
- }
3582
- if (panelName === "claude" && config.panels.claude.enabled) {
3583
- const vs = visualFeedback.getState("claude");
3584
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3585
- ClaudePanel,
3586
- {
3587
- data: claudeData,
3588
- countdown: isWatchMode ? countdowns.claude : null,
3589
- width,
3590
- justRefreshed: vs.justRefreshed
3591
- }
3592
- ) }, `panel-${panelName}-${index}`);
3593
- }
3594
- if (panelName === "other_sessions" && config.panels.other_sessions.enabled) {
3595
- const vs = visualFeedback.getState("other_sessions");
3596
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3597
- OtherSessionsPanel,
3598
- {
3599
- data: otherSessionsData,
3600
- countdown: isWatchMode ? countdowns.other_sessions : null,
3601
- width,
3602
- isRunning: vs.isRunning,
3603
- messageMaxLength: config.panels.other_sessions.messageMaxLength
3604
- }
3605
- ) }, `panel-${panelName}-${index}`);
3606
- }
3607
- const customConfig = config.customPanels?.[panelName];
3608
- if (customConfig?.enabled) {
3609
- const result = customPanelData[panelName];
3610
- if (!result) return null;
3611
- const vs = visualFeedback.getState(panelName);
3612
- const isManual = customConfig.interval === null;
3613
- const relativeTime = isManual ? formatRelativeTime3(result.timestamp) : void 0;
3614
- const countdown = !isManual && isWatchMode ? countdowns[panelName] : null;
3615
- return /* @__PURE__ */ jsx8(Box8, { marginTop, children: /* @__PURE__ */ jsx8(
3616
- GenericPanel,
3617
- {
3618
- data: result.data,
3619
- renderer: customConfig.renderer,
3620
- countdown,
3621
- relativeTime,
3622
- error: result.error,
3623
- width,
3624
- isRunning: vs.isRunning,
3625
- justRefreshed: vs.justRefreshed
3626
- }
3627
- ) }, `panel-${panelName}-${index}`);
3628
- }
3629
- return null;
3630
- }),
3859
+ config.panelOrder.map(
3860
+ (panelName, index) => renderPanel(panelName, width, index === 0 ? 0 : 1)
3861
+ ),
3631
3862
  isWatchMode && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, width, justifyContent: "space-between", children: [
3632
3863
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: statusBarItems.map((item, index) => /* @__PURE__ */ jsxs8(React.Fragment, { children: [
3633
3864
  index > 0 && " \xB7 ",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenthud",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
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",