agenthud 0.12.3 → 0.13.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.
package/README.md CHANGED
@@ -191,12 +191,12 @@ Output:
191
191
  | Flag | Default | Description |
192
192
  |------|---------|-------------|
193
193
  | `--date` | today | `YYYY-MM-DD`, `today`, `yesterday`, or `-Nd` (N days ago, local date) |
194
- | `--include` | `user,response,bash,edit,thinking` | Comma-separated types or `all` |
194
+ | `--include` | `user,response,bash,edit,thinking,task` | Comma-separated types or `all` |
195
195
  | `--format` | `markdown` | `markdown` or `json` |
196
196
  | `--detail-limit` | `120` | Max chars per detail field; `0` = unlimited |
197
197
  | `--with-git` | off | Merge git commits from each session's project into the timeline |
198
198
 
199
- `--include` types: `response`, `bash`, `edit`, `thinking`, `read`, `glob`, `user`
199
+ `--include` types: `response`, `bash`, `edit`, `thinking`, `read`, `glob`, `user`, `task` (Task tool delegations to subagents — surfaces the subagent's returned text so the LLM summary can see what the subagent actually did)
200
200
 
201
201
  ## Summary
202
202
 
@@ -262,7 +262,7 @@ refreshInterval: 2s
262
262
 
263
263
  # Activity filter presets (cycle with 'f' key in viewer)
264
264
  # Each list is one preset. Use "all" (or "*") to show everything.
265
- # Types: response, user, bash, edit, thinking, read, glob, commit
265
+ # Types: response, user, bash, edit, thinking, read, glob, commit, task
266
266
  filterPresets:
267
267
  - ["all"]
268
268
  - ["response", "user"]
@@ -270,7 +270,7 @@ filterPresets:
270
270
 
271
271
  # Defaults for `agenthud report` (CLI flags still win per-invocation).
272
272
  report:
273
- include: [user, response, bash, edit, thinking]
273
+ include: [user, response, bash, edit, thinking, task]
274
274
  detailLimit: 120
275
275
  withGit: false
276
276
  format: markdown
package/dist/index.js CHANGED
@@ -15,4 +15,4 @@ Error: Node.js ${MIN_NODE_VERSION}+ is required (current: ${process.version})
15
15
  process.exit(1);
16
16
  }
17
17
  if (!process.env.NODE_ENV) process.env.NODE_ENV = "production";
18
- import("./main-WHDPTTTD.js");
18
+ import("./main-UBXFOCNF.js");
@@ -23,7 +23,8 @@ var DEFAULT_INCLUDE_TYPES = [
23
23
  "response",
24
24
  "bash",
25
25
  "edit",
26
- "thinking"
26
+ "thinking",
27
+ "task"
27
28
  ];
28
29
  var ALLOWED_INCLUDE_TYPES = /* @__PURE__ */ new Set([
29
30
  "user",
@@ -33,7 +34,8 @@ var ALLOWED_INCLUDE_TYPES = /* @__PURE__ */ new Set([
33
34
  "thinking",
34
35
  "read",
35
36
  "glob",
36
- "commit"
37
+ "commit",
38
+ "task"
37
39
  ]);
38
40
  var DEFAULT_GLOBAL_CONFIG = {
39
41
  refreshIntervalMs: 2e3,
@@ -949,6 +951,10 @@ function buildToolDetailBody(name, input, result) {
949
951
  const content = result?.content ?? input?.content;
950
952
  if (content) return { text: content, kind: "code" };
951
953
  }
954
+ if (name === "Task") {
955
+ const content = result?.content;
956
+ if (content) return { text: content, kind: "code" };
957
+ }
952
958
  if (name === "Read") {
953
959
  const content = result?.file?.content;
954
960
  if (content) {
@@ -1123,6 +1129,7 @@ function activityMatchesInclude(activity, include) {
1123
1129
  return true;
1124
1130
  if (include.includes("glob") && (label === "glob" || label === "grep"))
1125
1131
  return true;
1132
+ if (include.includes("task") && label === "task") return true;
1126
1133
  return false;
1127
1134
  }
1128
1135
  function isSameLocalDay(a, b) {
@@ -1137,6 +1144,14 @@ function formatActivity(activity, limit) {
1137
1144
  const suffix = detail ? `: ${detail}` : "";
1138
1145
  return `[${time}] ${activity.icon} ${activity.label}${suffix}`;
1139
1146
  }
1147
+ function formatTaskBody(activity, limit) {
1148
+ if (activity.label !== "Task") return null;
1149
+ if (!activity.detailBody) return null;
1150
+ const body = truncateRaw(activity.detailBody, limit);
1151
+ return `<task-result>
1152
+ ${body}
1153
+ </task-result>`;
1154
+ }
1140
1155
  function formatDateString2(date) {
1141
1156
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
1142
1157
  }
@@ -1239,6 +1254,8 @@ function generateReport(sessions, options2) {
1239
1254
  lines.push("");
1240
1255
  for (const activity of activities) {
1241
1256
  lines.push(formatActivity(activity, detailLimit));
1257
+ const taskBody = formatTaskBody(activity, detailLimit);
1258
+ if (taskBody) lines.push(taskBody);
1242
1259
  }
1243
1260
  lines.push("");
1244
1261
  }
@@ -1302,8 +1319,8 @@ function truncateByWidth(text, maxWidth) {
1302
1319
  }
1303
1320
  var widthCache = /* @__PURE__ */ new Map();
1304
1321
  function getDisplayWidth(s) {
1305
- const cached = widthCache.get(s);
1306
- if (cached !== void 0) return cached;
1322
+ const cached2 = widthCache.get(s);
1323
+ if (cached2 !== void 0) return cached2;
1307
1324
  const w = stringWidth(s);
1308
1325
  widthCache.set(s, w);
1309
1326
  return w;
@@ -1688,8 +1705,28 @@ import { fileURLToPath as fileURLToPath2 } from "url";
1688
1705
 
1689
1706
  // src/utils/openInDefaultApp.ts
1690
1707
  import { spawn } from "child_process";
1691
- import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
1708
+ import { existsSync as existsSync4 } from "fs";
1692
1709
  import { join as join4 } from "path";
1710
+
1711
+ // src/utils/platform.ts
1712
+ import { readFileSync as readFileSync5 } from "fs";
1713
+ var cached = null;
1714
+ function isWSL() {
1715
+ if (cached !== null) return cached;
1716
+ if (process.env.WSL_DISTRO_NAME) {
1717
+ cached = true;
1718
+ return cached;
1719
+ }
1720
+ try {
1721
+ const ver = readFileSync5("/proc/version", "utf-8");
1722
+ cached = /microsoft|wsl/i.test(ver);
1723
+ } catch {
1724
+ cached = false;
1725
+ }
1726
+ return cached;
1727
+ }
1728
+
1729
+ // src/utils/openInDefaultApp.ts
1693
1730
  function buildOpenCommand(platform, path, opts = {}) {
1694
1731
  switch (platform) {
1695
1732
  case "darwin":
@@ -1703,15 +1740,6 @@ function buildOpenCommand(platform, path, opts = {}) {
1703
1740
  return null;
1704
1741
  }
1705
1742
  }
1706
- function isWSL() {
1707
- if (process.env.WSL_DISTRO_NAME) return true;
1708
- try {
1709
- const ver = readFileSync5("/proc/version", "utf-8");
1710
- return /microsoft|wsl/i.test(ver);
1711
- } catch {
1712
- return false;
1713
- }
1714
- }
1715
1743
  function commandExists(command) {
1716
1744
  const PATH = process.env.PATH ?? "";
1717
1745
  const sep = process.platform === "win32" ? ";" : ":";
@@ -2120,6 +2148,16 @@ function resolvePrompt(kind, override) {
2120
2148
  return "Summarize the input below.";
2121
2149
  }
2122
2150
  }
2151
+ function buildRangeMetaInput(dailyMarkdowns) {
2152
+ if (dailyMarkdowns.length === 0) return "";
2153
+ return dailyMarkdowns.map(
2154
+ ({ date, markdown }) => `<day date="${dateKey(date)}">
2155
+
2156
+ ${markdown}
2157
+
2158
+ </day>`
2159
+ ).join("\n\n");
2160
+ }
2123
2161
  function shouldUseRangeCache(force, dates, today, cacheExists) {
2124
2162
  if (force) return false;
2125
2163
  if (!cacheExists) return false;
@@ -2206,7 +2244,12 @@ function spawnClaude(opts) {
2206
2244
  resolve2({ code: 1, text: "", usage: null });
2207
2245
  }
2208
2246
  });
2247
+ let firstChunkFired = false;
2209
2248
  const writeText = (text) => {
2249
+ if (!firstChunkFired) {
2250
+ firstChunkFired = true;
2251
+ opts.onFirstChunk?.();
2252
+ }
2210
2253
  assembledText += text;
2211
2254
  if (opts.streamToStdout) process.stdout.write(text);
2212
2255
  cacheStream?.write(text);
@@ -2289,13 +2332,13 @@ var REPORT_TOKEN_WARN_THRESHOLD = 3e5;
2289
2332
  async function generateDailySummary(opts) {
2290
2333
  ensureUserPromptFile("daily");
2291
2334
  const isToday = isSameLocalDay2(opts.date, opts.today);
2292
- const cached = dailyCachePath(opts.date);
2335
+ const cached2 = dailyCachePath(opts.date);
2293
2336
  const dateLabel = dateKey(opts.date);
2294
- if (!isToday && !opts.force && existsSync6(cached)) {
2337
+ if (!isToday && !opts.force && existsSync6(cached2)) {
2295
2338
  try {
2296
- const content = readFileSync7(cached, "utf-8");
2339
+ const content = readFileSync7(cached2, "utf-8");
2297
2340
  if (opts.announce) {
2298
- process.stderr.write(`cached summary from ${cached}
2341
+ process.stderr.write(`cached summary from ${cached2}
2299
2342
  `);
2300
2343
  }
2301
2344
  if (opts.streamToStdout) {
@@ -2399,27 +2442,22 @@ async function generateDailySummary(opts) {
2399
2442
  }
2400
2443
  }
2401
2444
  }
2402
- const showTicker = opts.announce && !opts.streamToStdout;
2403
- if (opts.announce && !showTicker) {
2404
- process.stderr.write(
2405
- `sending to claude (this may take a minute)...
2406
-
2407
- `
2408
- );
2409
- }
2410
- const stopTicker = showTicker ? startStderrTicker("sending to claude") : null;
2445
+ const stopTicker = opts.announce ? startStderrTicker("sending to claude") : null;
2411
2446
  const prompt = resolvePrompt("daily", opts.promptOverride);
2412
2447
  const result = await spawnClaude({
2413
2448
  prompt,
2414
2449
  stdin: reportMarkdown,
2415
- cachePath: cached,
2450
+ cachePath: cached2,
2416
2451
  streamToStdout: opts.streamToStdout,
2417
- model: opts.model
2452
+ model: opts.model,
2453
+ onFirstChunk: () => {
2454
+ if (stopTicker) stopTicker();
2455
+ }
2418
2456
  });
2419
2457
  if (stopTicker) stopTicker();
2420
2458
  if (opts.announce && result.code === 0) {
2421
2459
  process.stderr.write("\n");
2422
- process.stderr.write(`saved to ${cached}
2460
+ process.stderr.write(`saved to ${cached2}
2423
2461
  `);
2424
2462
  if (result.usage) {
2425
2463
  process.stderr.write(`${formatUsage(result.usage)}
@@ -2572,33 +2610,24 @@ async function runRangeSummary(options2) {
2572
2610
  }
2573
2611
  return 0;
2574
2612
  }
2575
- const metaInput = dailyMarkdowns.map(({ date, markdown }) => `# ${dateKey(date)}
2576
-
2577
- ${markdown}`).join("\n\n---\n\n");
2613
+ const metaInput = buildRangeMetaInput(dailyMarkdowns);
2578
2614
  process.stderr.write(
2579
2615
  `
2580
2616
  combining ${dailyMarkdowns.length} daily summaries into range summary...
2581
2617
  `
2582
2618
  );
2583
2619
  const metaStreams = !options2.open;
2584
- if (!metaStreams) {
2585
- } else {
2586
- process.stderr.write(
2587
- `sending to claude (this may take a minute)...
2588
-
2589
- `
2590
- );
2591
- }
2592
- const stopMetaTicker = metaStreams ? null : startStderrTicker("sending to claude");
2620
+ const stopMetaTicker = startStderrTicker("sending to claude");
2593
2621
  const metaPrompt = resolvePrompt("range");
2594
2622
  const metaResult = await spawnClaude({
2595
2623
  prompt: metaPrompt,
2596
2624
  stdin: metaInput,
2597
2625
  cachePath: rangeCache,
2598
2626
  streamToStdout: metaStreams,
2599
- model: options2.model
2627
+ model: options2.model,
2628
+ onFirstChunk: () => stopMetaTicker()
2600
2629
  });
2601
- if (stopMetaTicker) stopMetaTicker();
2630
+ stopMetaTicker();
2602
2631
  if (metaResult.code !== 0) {
2603
2632
  return metaResult.code;
2604
2633
  }
@@ -4709,10 +4738,14 @@ function installAltScreenCleanup() {
4709
4738
 
4710
4739
  // src/utils/legacyConfig.ts
4711
4740
  import { join as join7, resolve } from "path";
4712
- function isLegacyProjectConfig(cwd, home) {
4741
+ var WSL_WINDOWS_USER_HOME = /^\/mnt\/[a-z]\/Users\/[^/]+\/?$/i;
4742
+ function isLegacyProjectConfig(cwd, home, opts = {}) {
4713
4743
  const legacy = resolve(join7(cwd, ".agenthud", "config.yaml"));
4714
4744
  const global = resolve(join7(home, ".agenthud", "config.yaml"));
4715
- return legacy !== global;
4745
+ if (legacy === global) return false;
4746
+ const wsl = opts.isWSL ?? isWSL();
4747
+ if (wsl && WSL_WINDOWS_USER_HOME.test(cwd)) return false;
4748
+ return true;
4716
4749
  }
4717
4750
 
4718
4751
  // src/main.ts
@@ -1,5 +1,18 @@
1
- The following are daily engineering summaries from a date range, separated by `---` lines.
2
- Each daily summary uses the structure: Context / Key Accomplishments / Technical Insights / Major Code Changes / Open Questions.
1
+ The input contains daily engineering summaries from a date range.
2
+
3
+ Each day is wrapped in an XML tag with its date as an attribute:
4
+
5
+ <day date="YYYY-MM-DD">
6
+ (that day's summary — markdown using sections like
7
+ Context / Key Accomplishments / Technical Insights /
8
+ Major Code Changes / Open Questions)
9
+ </day>
10
+
11
+ Multiple `<day>` blocks follow in chronological order. Use the
12
+ `date` attribute as the authoritative date for that block — do not
13
+ infer dates from headings or text inside the block. Any `# YYYY-MM-DD`
14
+ heading or `---` line you see inside a `<day>` block is part of the
15
+ day's content, not a structural divider.
3
16
 
4
17
  Write a range-level synthesis in English.
5
18
  Aim for roughly 400-700 words total — the value of a range summary is cross-day pattern extraction, not re-summarization.
@@ -15,6 +28,8 @@ The point of a range summary is to surface what only becomes visible by looking
15
28
  - outcomes that matter at the range level, not at any single day
16
29
  - work that started in one day and continued, completed, or was abandoned later
17
30
 
31
+ When you reference a specific day, use its `date` attribute value verbatim (`2026-06-07`), not a relative term like "Monday" or "yesterday".
32
+
18
33
  Use the following format:
19
34
 
20
35
  ## Range Overview
@@ -32,4 +47,4 @@ Themes that surfaced on more than one day: repeated debugging classes, recurring
32
47
  ## Carried-Over / Unfinished Work
33
48
  Work still in progress at the end of the range, or open questions that persisted across multiple days.
34
49
 
35
- Daily summaries:
50
+ Daily summaries follow:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenthud",
3
- "version": "0.12.3",
3
+ "version": "0.13.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",