@sooneocean/claude-hud 0.7.0 → 0.9.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 (66) hide show
  1. package/.claude-plugin/plugin.json +5 -1
  2. package/commands/diff.md +42 -0
  3. package/commands/preset.md +44 -0
  4. package/commands/report.md +6 -0
  5. package/commands/shortcuts.md +35 -0
  6. package/commands/tag.md +29 -0
  7. package/dist/alert.d.ts +1 -0
  8. package/dist/alert.d.ts.map +1 -1
  9. package/dist/alert.js +24 -0
  10. package/dist/alert.js.map +1 -1
  11. package/dist/config.d.ts +2 -1
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +33 -13
  14. package/dist/config.js.map +1 -1
  15. package/dist/i18n.d.ts +6 -0
  16. package/dist/i18n.d.ts.map +1 -1
  17. package/dist/i18n.js +18 -0
  18. package/dist/i18n.js.map +1 -1
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +26 -8
  22. package/dist/index.js.map +1 -1
  23. package/dist/perf-guard.d.ts +3 -0
  24. package/dist/perf-guard.d.ts.map +1 -0
  25. package/dist/perf-guard.js +33 -0
  26. package/dist/perf-guard.js.map +1 -0
  27. package/dist/presets.d.ts +14 -0
  28. package/dist/presets.d.ts.map +1 -0
  29. package/dist/presets.js +47 -0
  30. package/dist/presets.js.map +1 -0
  31. package/dist/render/lines/identity.d.ts.map +1 -1
  32. package/dist/render/lines/identity.js +3 -0
  33. package/dist/render/lines/identity.js.map +1 -1
  34. package/dist/render/lines/usage.js +6 -6
  35. package/dist/render/lines/usage.js.map +1 -1
  36. package/dist/render/todos-line.d.ts.map +1 -1
  37. package/dist/render/todos-line.js +3 -1
  38. package/dist/render/todos-line.js.map +1 -1
  39. package/dist/render/tools-line.d.ts.map +1 -1
  40. package/dist/render/tools-line.js +3 -1
  41. package/dist/render/tools-line.js.map +1 -1
  42. package/dist/session-history.d.ts +3 -0
  43. package/dist/session-history.d.ts.map +1 -1
  44. package/dist/session-history.js +16 -0
  45. package/dist/session-history.js.map +1 -1
  46. package/dist/session-stats.d.ts +7 -0
  47. package/dist/session-stats.d.ts.map +1 -1
  48. package/dist/session-stats.js +17 -0
  49. package/dist/session-stats.js.map +1 -1
  50. package/dist/types.d.ts +2 -0
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/types.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/alert.ts +23 -0
  55. package/src/config.ts +35 -15
  56. package/src/i18n.ts +24 -0
  57. package/src/index.ts +31 -9
  58. package/src/perf-guard.ts +43 -0
  59. package/src/presets.ts +56 -0
  60. package/src/render/lines/identity.ts +4 -0
  61. package/src/render/lines/usage.ts +6 -6
  62. package/src/render/todos-line.ts +3 -1
  63. package/src/render/tools-line.ts +3 -1
  64. package/src/session-history.ts +19 -0
  65. package/src/session-stats.ts +27 -0
  66. package/src/types.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"session-stats.js","sourceRoot":"","sources":["../src/session-stats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-stats.js","sourceRoot":"","sources":["../src/session-stats.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -5,6 +5,7 @@ import type { McpServerInfo } from './mcp-monitor.js';
5
5
  import type { Locale } from './i18n.js';
6
6
  import type { CustomWidget } from './custom-widgets.js';
7
7
  import type { Suggestion } from './suggestions.js';
8
+ import type { ResumeInfo } from './session-stats.js';
8
9
  export interface StdinData {
9
10
  transcript_path?: string;
10
11
  cwd?: string;
@@ -130,5 +131,6 @@ export interface RenderContext {
130
131
  customWidgets: CustomWidget[];
131
132
  suggestions: Suggestion[];
132
133
  rateLimitEta: string | null;
134
+ resumeInfo: ResumeInfo | null;
133
135
  }
134
136
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAqEA,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,IAAe;IAC5C,OAAO,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC;AACxD,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsEA,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,IAAe;IAC5C,OAAO,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC;AACxD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sooneocean/claude-hud",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Enhanced real-time statusline HUD for Claude Code — with cache, alerts, frameworks, themes, and Dashboard Rich visuals",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/alert.ts CHANGED
@@ -129,6 +129,29 @@ export function predictRateLimitHit(
129
129
  return `~${hours}h ${mins}m`;
130
130
  }
131
131
 
132
+ export function sendWebhook(url: string, alert: Alert): void {
133
+ try {
134
+ const payload = JSON.stringify({
135
+ type: alert.type,
136
+ message: alert.message,
137
+ timestamp: new Date().toISOString(),
138
+ source: 'claude-hud',
139
+ });
140
+
141
+ // Fire and forget — don't block HUD rendering
142
+ fetch(url, {
143
+ method: 'POST',
144
+ headers: { 'Content-Type': 'application/json' },
145
+ body: payload,
146
+ signal: AbortSignal.timeout(3000),
147
+ }).catch(() => {
148
+ if (DEBUG) console.error('[claude-hud:alert] webhook failed');
149
+ });
150
+ } catch {
151
+ if (DEBUG) console.error('[claude-hud:alert] webhook error');
152
+ }
153
+ }
154
+
132
155
  export function runAlertHook(hook: string, alert: Alert): void {
133
156
  try {
134
157
  const env = {
package/src/config.ts CHANGED
@@ -94,7 +94,8 @@ export interface HudConfig {
94
94
  context: { warningThreshold: number; criticalThreshold: number; actions: AlertAction };
95
95
  usage5h: { warningThreshold: number; criticalThreshold: number; actions: AlertAction };
96
96
  usage7d: { warningThreshold: number; actions: AlertAction };
97
- hook?: string; // shell command to run on any alert trigger
97
+ hook?: string; // shell command to run on any alert trigger
98
+ webhook?: string; // URL to POST alert data as JSON
98
99
  };
99
100
  locale: Locale;
100
101
  schemaVersion: number;
@@ -501,6 +502,7 @@ export function mergeConfig(userConfig: Partial<HudConfig>): HudConfig {
501
502
  actions: mergeAlertActions(migrated.alerts?.usage7d?.actions, DEFAULT_CONFIG.alerts.usage7d.actions),
502
503
  },
503
504
  hook: typeof migrated.alerts?.hook === 'string' ? migrated.alerts.hook : undefined,
505
+ webhook: typeof migrated.alerts?.webhook === 'string' ? migrated.alerts.webhook : undefined,
504
506
  };
505
507
 
506
508
  const locale = (migrated.locale === 'en' || migrated.locale === 'zh' || migrated.locale === 'ja')
@@ -557,27 +559,45 @@ export function validateConfigWithWarnings(userConfig: Record<string, unknown>):
557
559
  return warnings;
558
560
  }
559
561
 
560
- export async function loadConfig(): Promise<HudConfig> {
562
+ export async function loadConfig(cwd?: string): Promise<HudConfig> {
561
563
  const configPath = getConfigPath();
562
564
  const DEBUG = process.env.DEBUG?.includes('claude-hud') || process.env.DEBUG === '*';
563
565
 
564
- try {
565
- if (!fs.existsSync(configPath)) {
566
- return DEFAULT_CONFIG;
567
- }
568
-
569
- const content = fs.readFileSync(configPath, 'utf-8');
570
- const userConfig = JSON.parse(content) as Partial<HudConfig>;
566
+ let projectConfig: Partial<HudConfig> = {};
567
+ let userConfig: Partial<HudConfig> = {};
571
568
 
572
- const warnings = validateConfigWithWarnings(userConfig as Record<string, unknown>);
573
- if (DEBUG && warnings.length > 0) {
574
- for (const w of warnings) {
575
- console.error(`[claude-hud:config] ⚠ ${w}`);
569
+ // 1. Read project-level config (.claude-hud.json in project root)
570
+ if (cwd) {
571
+ try {
572
+ const projectPath = path.join(cwd, '.claude-hud.json');
573
+ if (fs.existsSync(projectPath)) {
574
+ projectConfig = JSON.parse(fs.readFileSync(projectPath, 'utf-8'));
575
+ if (DEBUG) console.error('[claude-hud:config] loaded project config from .claude-hud.json');
576
576
  }
577
+ } catch {
578
+ if (DEBUG) console.error('[claude-hud:config] error reading .claude-hud.json');
577
579
  }
580
+ }
578
581
 
579
- return mergeConfig(userConfig);
582
+ // 2. Read user config (existing logic)
583
+ try {
584
+ if (fs.existsSync(configPath)) {
585
+ const content = fs.readFileSync(configPath, 'utf-8');
586
+ userConfig = JSON.parse(content) as Partial<HudConfig>;
587
+ }
580
588
  } catch {
581
- return DEFAULT_CONFIG;
589
+ // ignore
582
590
  }
591
+
592
+ // 3. Merge: defaults <- project <- user (user overrides project)
593
+ const merged = { ...projectConfig, ...userConfig };
594
+
595
+ const warnings = validateConfigWithWarnings(merged as Record<string, unknown>);
596
+ if (DEBUG && warnings.length > 0) {
597
+ for (const w of warnings) {
598
+ console.error(`[claude-hud:config] ⚠ ${w}`);
599
+ }
600
+ }
601
+
602
+ return mergeConfig(merged);
583
603
  }
package/src/i18n.ts CHANGED
@@ -11,6 +11,12 @@ interface Labels {
11
11
  resets: string;
12
12
  compact: string;
13
13
  tokPerMin: string;
14
+ resetsIn: string;
15
+ syncing: string;
16
+ err: string;
17
+ total: string;
18
+ limit: string;
19
+ warn: string;
14
20
  }
15
21
 
16
22
  const LABELS: Record<Locale, Labels> = {
@@ -25,6 +31,12 @@ const LABELS: Record<Locale, Labels> = {
25
31
  resets: 'resets in',
26
32
  compact: 'compact',
27
33
  tokPerMin: 'tok/m',
34
+ resetsIn: 'resets in',
35
+ syncing: 'syncing...',
36
+ err: 'err',
37
+ total: 'total',
38
+ limit: 'limit',
39
+ warn: 'Warning',
28
40
  },
29
41
  zh: {
30
42
  context: '上下文',
@@ -37,6 +49,12 @@ const LABELS: Record<Locale, Labels> = {
37
49
  resets: '重置於',
38
50
  compact: '壓縮',
39
51
  tokPerMin: 'tok/m',
52
+ resetsIn: '重置於',
53
+ syncing: '同步中...',
54
+ err: '錯誤',
55
+ total: '總計',
56
+ limit: '上限',
57
+ warn: '警告',
40
58
  },
41
59
  ja: {
42
60
  context: 'コンテキスト',
@@ -49,6 +67,12 @@ const LABELS: Record<Locale, Labels> = {
49
67
  resets: 'リセット',
50
68
  compact: 'コンパクト',
51
69
  tokPerMin: 'tok/m',
70
+ resetsIn: 'リセット',
71
+ syncing: '同期中...',
72
+ err: 'エラー',
73
+ total: '合計',
74
+ limit: '制限',
75
+ warn: '警告',
52
76
  },
53
77
  };
54
78
 
package/src/index.ts CHANGED
@@ -5,15 +5,16 @@ import { countConfigs } from './config-reader.js';
5
5
  import { getGitStatus } from './git.js';
6
6
  import { getUsage } from './usage-api.js';
7
7
  import { loadConfig } from './config.js';
8
+ import type { HudConfig } from './config.js';
8
9
  import { parseExtraCmdArg, runExtraCmd } from './extra-cmd.js';
9
10
  import type { RenderContext } from './types.js';
10
11
  import { fileURLToPath } from 'node:url';
11
12
  import { realpathSync } from 'node:fs';
12
13
  import { getDefaultCacheDir, readCache, writeCache, readLatency, writeLatency } from './cache.js';
13
14
  import { loadProviders, fetchAllProviders } from './providers/index.js';
14
- import { evaluateAlerts, shouldBell, sendNotification, recordAlertHistory, runAlertHook, predictRateLimitHit } from './alert.js';
15
+ import { evaluateAlerts, shouldBell, sendNotification, recordAlertHistory, runAlertHook, predictRateLimitHit, sendWebhook } from './alert.js';
15
16
  import { calculateBurnRate, recordTokenSnapshot } from './burn-rate.js';
16
- import { updateSessionStats, getSessionStats, getSparkline, updatePromptStats, updateAgentStats } from './session-stats.js';
17
+ import { updateSessionStats, getSessionStats, getSparkline, updatePromptStats, updateAgentStats, detectResume, getResumeInfo } from './session-stats.js';
17
18
  import { getTerminalWidth } from './utils/terminal.js';
18
19
  import { estimateCost } from './cost-tracker.js';
19
20
  import { saveCurrentSession, getLastSession, formatSessionSummary } from './session-history.js';
@@ -25,6 +26,7 @@ import { loadCustomWidgets } from './custom-widgets.js';
25
26
  import { updateTokenAnalytics } from './token-analytics.js';
26
27
  import { getSuggestions } from './suggestions.js';
27
28
  import { autoTuneConfig } from './auto-tune.js';
29
+ import { shouldDegrade, recordExecutionTime } from './perf-guard.js';
28
30
 
29
31
  export type MainDeps = {
30
32
  readStdin: typeof readStdin;
@@ -32,7 +34,7 @@ export type MainDeps = {
32
34
  countConfigs: typeof countConfigs;
33
35
  getGitStatus: typeof getGitStatus;
34
36
  getUsage: typeof getUsage;
35
- loadConfig: typeof loadConfig;
37
+ loadConfig: (cwd?: string) => Promise<HudConfig>;
36
38
  parseExtraCmdArg: typeof parseExtraCmdArg;
37
39
  runExtraCmd: typeof runExtraCmd;
38
40
  render: typeof render;
@@ -48,6 +50,7 @@ function timer() {
48
50
  export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
49
51
  const DEBUG = process.env.DEBUG?.includes('claude-hud') || process.env.DEBUG === '*';
50
52
  const tTotal = timer();
53
+ const perfStart = Date.now();
51
54
 
52
55
  const deps: MainDeps = {
53
56
  readStdin,
@@ -55,7 +58,7 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
55
58
  countConfigs,
56
59
  getGitStatus,
57
60
  getUsage,
58
- loadConfig,
61
+ loadConfig: (cwd?: string) => loadConfig(cwd),
59
62
  parseExtraCmdArg,
60
63
  runExtraCmd,
61
64
  render,
@@ -89,8 +92,11 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
89
92
 
90
93
  const cacheDir = getDefaultCacheDir();
91
94
 
95
+ const degradeMode = shouldDegrade(cacheDir);
96
+ if (DEBUG && degradeMode) console.error('[claude-hud:perf] running in degrade mode');
97
+
92
98
  const t3 = timer();
93
- let config = await deps.loadConfig();
99
+ let config = await deps.loadConfig(stdin.cwd);
94
100
  if (DEBUG) console.error(`[claude-hud:timing] loadConfig: ${t3()}ms`);
95
101
  config = autoTuneConfig(config, getTerminalWidth(), cacheDir);
96
102
  const t4 = timer();
@@ -121,16 +127,16 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
121
127
 
122
128
  const sessionDuration = formatSessionDuration(transcript.sessionStart, deps.now);
123
129
 
124
- // Framework providers
130
+ // Framework providers — skip if degrading
125
131
  let frameworkStatus: RenderContext['frameworkStatus'] = [];
126
- if (config.display.showFrameworks) {
132
+ if (config.display.showFrameworks && !degradeMode) {
127
133
  const providers = loadProviders(config.frameworks, cacheDir);
128
134
  frameworkStatus = await fetchAllProviders(providers);
129
135
  }
130
136
 
131
- // Token analytics (data collection only, no HUD display)
137
+ // Token analytics (data collection only, no HUD display) — skip if degrading
132
138
  const inputTokens = stdin.context_window?.current_usage?.input_tokens;
133
- if (inputTokens) {
139
+ if (inputTokens && !degradeMode) {
134
140
  updateTokenAnalytics(inputTokens, transcript.tools, cacheDir);
135
141
  }
136
142
 
@@ -155,6 +161,13 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
155
161
  // Context percent
156
162
  const contextPercent = getContextPercent(stdin);
157
163
 
164
+ // Session resume detection — detect autocompact by large context drop
165
+ const prevContextPercent = readCache<number>('prev-context-percent', 86400000, cacheDir);
166
+ const contextSizeForResume = stdin.context_window?.context_window_size ?? 0;
167
+ detectResume(contextPercent, prevContextPercent, contextSizeForResume, cacheDir);
168
+ writeCache('prev-context-percent', contextPercent, cacheDir);
169
+ const resumeInfo = getResumeInfo(cacheDir);
170
+
158
171
  // Agent efficiency tracking
159
172
  if (transcript.agents.length > 0) {
160
173
  updateAgentStats(transcript.agents, cacheDir);
@@ -203,6 +216,12 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
203
216
  runAlertHook(config.alerts.hook as string, alert);
204
217
  }
205
218
  }
219
+
220
+ if (config.alerts.webhook) {
221
+ for (const alert of alerts.filter(a => a.type.includes('critical'))) {
222
+ sendWebhook(config.alerts.webhook, alert);
223
+ }
224
+ }
206
225
  }
207
226
 
208
227
  // Rate limit prediction
@@ -272,6 +291,7 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
272
291
  locale: config.locale ?? detectLocale(),
273
292
  customWidgets,
274
293
  rateLimitEta,
294
+ resumeInfo,
275
295
  };
276
296
  const suggestions = config.display.showAlerts
277
297
  ? getSuggestions(suggestionInput as RenderContext)
@@ -286,6 +306,8 @@ export async function main(overrides: Partial<MainDeps> = {}): Promise<void> {
286
306
  deps.render(ctx);
287
307
  if (DEBUG) console.error(`[claude-hud:timing] render: ${t6()}ms`);
288
308
  if (DEBUG) console.error(`[claude-hud:timing] total: ${tTotal()}ms`);
309
+
310
+ recordExecutionTime(Date.now() - perfStart, cacheDir);
289
311
  } catch (error) {
290
312
  deps.log('[claude-hud] Error:', error instanceof Error ? error.message : 'Unknown error');
291
313
  }
@@ -0,0 +1,43 @@
1
+ import { readCache, writeCache } from './cache.js';
2
+
3
+ const DEBUG = process.env.DEBUG?.includes('claude-hud') || process.env.DEBUG === '*';
4
+ const PERF_KEY = 'perf-history';
5
+ const TTL = 24 * 60 * 60 * 1000;
6
+ const BUDGET_MS = 250; // Leave 50ms margin from 300ms
7
+
8
+ interface PerfHistory {
9
+ recentTimes: number[]; // last 10 execution times
10
+ degradeMode: boolean;
11
+ }
12
+
13
+ export function shouldDegrade(cacheDir: string): boolean {
14
+ const history = readCache<PerfHistory>(PERF_KEY, TTL, cacheDir);
15
+ return history?.degradeMode ?? false;
16
+ }
17
+
18
+ export function recordExecutionTime(ms: number, cacheDir: string): void {
19
+ const history = readCache<PerfHistory>(PERF_KEY, TTL, cacheDir) ?? {
20
+ recentTimes: [],
21
+ degradeMode: false,
22
+ };
23
+
24
+ history.recentTimes.push(ms);
25
+ if (history.recentTimes.length > 10) history.recentTimes.shift();
26
+
27
+ // Check if average of last 5 exceeds budget
28
+ const recent5 = history.recentTimes.slice(-5);
29
+ if (recent5.length >= 5) {
30
+ const avg = recent5.reduce((a, b) => a + b, 0) / recent5.length;
31
+ const wasDegrade = history.degradeMode;
32
+ history.degradeMode = avg > BUDGET_MS;
33
+
34
+ if (history.degradeMode && !wasDegrade && DEBUG) {
35
+ console.error(`[claude-hud:perf] degrading — avg ${Math.round(avg)}ms > ${BUDGET_MS}ms budget`);
36
+ }
37
+ if (!history.degradeMode && wasDegrade && DEBUG) {
38
+ console.error(`[claude-hud:perf] recovered — avg ${Math.round(avg)}ms`);
39
+ }
40
+ }
41
+
42
+ writeCache(PERF_KEY, history, cacheDir);
43
+ }
package/src/presets.ts ADDED
@@ -0,0 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import type { HudConfig } from './config.js';
4
+
5
+ const DEBUG = process.env.DEBUG?.includes('claude-hud') || process.env.DEBUG === '*';
6
+
7
+ interface Preset {
8
+ name: string;
9
+ description: string;
10
+ config: Partial<HudConfig>;
11
+ createdAt: string;
12
+ }
13
+
14
+ function getPresetsPath(): string {
15
+ const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(process.env.HOME || '', '.claude');
16
+ return path.join(configDir, 'plugins', 'claude-hud', 'presets.json');
17
+ }
18
+
19
+ export function loadPresets(): Preset[] {
20
+ try {
21
+ return JSON.parse(fs.readFileSync(getPresetsPath(), 'utf-8'));
22
+ } catch {
23
+ return [];
24
+ }
25
+ }
26
+
27
+ export function savePreset(name: string, description: string, config: Partial<HudConfig>): void {
28
+ const presets = loadPresets();
29
+ const existing = presets.findIndex(p => p.name === name);
30
+ const preset: Preset = { name, description, config, createdAt: new Date().toISOString() };
31
+ if (existing >= 0) presets[existing] = preset;
32
+ else presets.push(preset);
33
+
34
+ const dir = path.dirname(getPresetsPath());
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ fs.writeFileSync(getPresetsPath(), JSON.stringify(presets, null, 2));
37
+ if (DEBUG) console.error(`[claude-hud:presets] saved preset "${name}"`);
38
+ }
39
+
40
+ export function getPreset(name: string): Preset | undefined {
41
+ return loadPresets().find(p => p.name === name);
42
+ }
43
+
44
+ export function deletePreset(name: string): boolean {
45
+ const presets = loadPresets();
46
+ const idx = presets.findIndex(p => p.name === name);
47
+ if (idx < 0) return false;
48
+ presets.splice(idx, 1);
49
+ fs.writeFileSync(getPresetsPath(), JSON.stringify(presets, null, 2));
50
+ if (DEBUG) console.error(`[claude-hud:presets] deleted preset "${name}"`);
51
+ return true;
52
+ }
53
+
54
+ export function exportPresetAsJson(preset: Preset): string {
55
+ return JSON.stringify(preset, null, 2);
56
+ }
@@ -117,6 +117,10 @@ export function renderIdentityLine(ctx: RenderContext): string {
117
117
  line += dim(` (${ordinal(ctx.sessionStats.autocompactCount)} compact)`);
118
118
  }
119
119
 
120
+ if (ctx.resumeInfo) {
121
+ line += ` ${dim(`↓${ctx.resumeInfo.preCompactPercent}→${ctx.resumeInfo.postCompactPercent}%`)}`;
122
+ }
123
+
120
124
  if (!isNarrow && ctx.sparkline && ctx.sparkline.length >= 3) {
121
125
  line += ` ${renderHeatmap(ctx.sparkline)}`;
122
126
  }
@@ -34,7 +34,7 @@ export function renderUsageLine(ctx: RenderContext): string | null {
34
34
  const resetTime = ctx.usageData.fiveHour === 100
35
35
  ? formatResetTime(ctx.usageData.fiveHourResetAt)
36
36
  : formatResetTime(ctx.usageData.sevenDayResetAt);
37
- return `${label} ${critical(`⚠ Limit reached${resetTime ? ` (resets ${resetTime})` : ''}`, colors)}`;
37
+ return `${label} ${critical(`⚠ ${labels.limitReached}${resetTime ? ` (${labels.resetsIn} ${resetTime})` : ''}`, colors)}`;
38
38
  }
39
39
 
40
40
  const threshold = display?.usageThreshold ?? 0;
@@ -53,25 +53,25 @@ export function renderUsageLine(ctx: RenderContext): string | null {
53
53
  const barStyle = display?.barStyle ?? 'classic';
54
54
  const fiveHourPart = usageBarEnabled
55
55
  ? (fiveHourReset
56
- ? `${quotaBar(fiveHour ?? 0, getAdaptiveBarWidth(), colors, barStyle)} ${fiveHourDisplay} (resets in ${fiveHourReset})`
56
+ ? `${quotaBar(fiveHour ?? 0, getAdaptiveBarWidth(), colors, barStyle)} ${fiveHourDisplay} (${labels.resetsIn} ${fiveHourReset})`
57
57
  : `${quotaBar(fiveHour ?? 0, getAdaptiveBarWidth(), colors, barStyle)} ${fiveHourDisplay}`)
58
58
  : (fiveHourReset
59
- ? `5h: ${fiveHourDisplay} (resets in ${fiveHourReset})`
59
+ ? `5h: ${fiveHourDisplay} (${labels.resetsIn} ${fiveHourReset})`
60
60
  : `5h: ${fiveHourDisplay}`);
61
61
 
62
62
  const sevenDayThreshold = display?.sevenDayThreshold ?? 80;
63
63
  const syncingSuffix = ctx.usageData.apiError === 'rate-limited'
64
- ? ` ${dim('(syncing...)')}`
64
+ ? ` ${dim(`(${labels.syncing})`)}`
65
65
  : '';
66
66
  if (sevenDay !== null && sevenDay >= sevenDayThreshold) {
67
67
  const sevenDayDisplay = formatUsagePercent(sevenDay, colors);
68
68
  const sevenDayReset = formatResetTime(ctx.usageData.sevenDayResetAt);
69
69
  const sevenDayPart = usageBarEnabled
70
70
  ? (sevenDayReset
71
- ? `${quotaBar(sevenDay, getAdaptiveBarWidth(), colors, barStyle)} ${sevenDayDisplay} (resets in ${sevenDayReset})`
71
+ ? `${quotaBar(sevenDay, getAdaptiveBarWidth(), colors, barStyle)} ${sevenDayDisplay} (${labels.resetsIn} ${sevenDayReset})`
72
72
  : `${quotaBar(sevenDay, getAdaptiveBarWidth(), colors, barStyle)} ${sevenDayDisplay}`)
73
73
  : (sevenDayReset
74
- ? `7d: ${sevenDayDisplay} (resets in ${sevenDayReset})`
74
+ ? `7d: ${sevenDayDisplay} (${labels.resetsIn} ${sevenDayReset})`
75
75
  : `7d: ${sevenDayDisplay}`);
76
76
  let result = `${label} ${fiveHourPart} ${dim('│')} ${sevenDayPart}${syncingSuffix}`;
77
77
  if (ctx.rateLimitEta) {
@@ -1,8 +1,10 @@
1
1
  import type { RenderContext } from '../types.js';
2
2
  import { yellow, green, dim, claudeOrange } from './colors.js';
3
3
  import { truncateString } from '../utils/format.js';
4
+ import { getLabels } from '../i18n.js';
4
5
 
5
6
  export function renderTodosLine(ctx: RenderContext): string | null {
7
+ const labels = getLabels(ctx.locale || 'en');
6
8
  const { todos } = ctx.transcript;
7
9
 
8
10
  if (!todos || todos.length === 0) {
@@ -15,7 +17,7 @@ export function renderTodosLine(ctx: RenderContext): string | null {
15
17
 
16
18
  if (!inProgress) {
17
19
  if (completed === total && total > 0) {
18
- return `${green('✓')} All todos complete ${dim(`(${completed}/${total})`)}`;
20
+ return `${green('✓')} ${labels.allComplete} ${dim(`(${completed}/${total})`)}`;
19
21
  }
20
22
  return null;
21
23
  }
@@ -1,8 +1,10 @@
1
1
  import type { RenderContext } from '../types.js';
2
2
  import { yellow, green, cyan, dim, magenta, red } from './colors.js';
3
3
  import { truncatePath } from '../utils/format.js';
4
+ import { getLabels } from '../i18n.js';
4
5
 
5
6
  export function renderToolsLine(ctx: RenderContext): string | null {
7
+ const labels = getLabels(ctx.locale || 'en');
6
8
  const { tools } = ctx.transcript;
7
9
 
8
10
  if (tools.length === 0) {
@@ -36,7 +38,7 @@ export function renderToolsLine(ctx: RenderContext): string | null {
36
38
  // Show error count if any tools failed
37
39
  const errorCount = ctx.transcript.tools.filter(t => t.status === 'error').length;
38
40
  if (errorCount > 0) {
39
- parts.push(`${red('✘')} ${errorCount} err`);
41
+ parts.push(`${red('✘')} ${errorCount} ${labels.err}`);
40
42
  }
41
43
 
42
44
  if (ctx.config.display.mergeToolsAgents && ctx.transcript.agents.length > 0) {
@@ -12,6 +12,7 @@ export interface SessionRecord {
12
12
  autocompactCount: number;
13
13
  totalToolCalls: number;
14
14
  totalAgentRuns: number;
15
+ tags?: string[];
15
16
  }
16
17
 
17
18
  function getHistoryPath(): string {
@@ -57,6 +58,24 @@ export function getLastSession(): SessionRecord | null {
57
58
  return history.length >= 2 ? history[history.length - 2] : null;
58
59
  }
59
60
 
61
+ export function tagCurrentSession(tags: string[], _cacheDir: string): void {
62
+ const history = loadHistory();
63
+ if (history.length === 0) return;
64
+
65
+ // Tag the most recent session
66
+ const last = history[history.length - 1];
67
+ last.tags = [...new Set([...(last.tags || []), ...tags])];
68
+
69
+ const dir = path.dirname(getHistoryPath());
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ fs.writeFileSync(getHistoryPath(), JSON.stringify(history, null, 2));
72
+ if (DEBUG) console.error(`[claude-hud:session-history] tagged session with: ${tags.join(', ')}`);
73
+ }
74
+
75
+ export function getSessionsByTag(tag: string): SessionRecord[] {
76
+ return loadHistory().filter(s => s.tags?.includes(tag));
77
+ }
78
+
60
79
  export function formatSessionSummary(record: SessionRecord): string {
61
80
  return `Last: ${record.model} ${record.duration} | ${record.peakContextPercent}% peak | ${record.totalToolCalls} tools | ${record.autocompactCount} compacts`;
62
81
  }
@@ -1,6 +1,33 @@
1
1
  import { readCache, writeCache } from './cache.js';
2
2
  import type { SessionStats } from './types.js';
3
3
 
4
+ export interface ResumeInfo {
5
+ preCompactPercent: number;
6
+ postCompactPercent: number;
7
+ tokensRecovered: number;
8
+ }
9
+
10
+ const RESUME_KEY = 'resume-info';
11
+
12
+ export function detectResume(contextPercent: number, prevPercent: number | null, contextSize: number, cacheDir: string): ResumeInfo | null {
13
+ if (prevPercent === null || prevPercent - contextPercent < 20) return null;
14
+
15
+ const tokensRecovered = Math.round((prevPercent - contextPercent) / 100 * contextSize);
16
+ const info: ResumeInfo = {
17
+ preCompactPercent: prevPercent,
18
+ postCompactPercent: contextPercent,
19
+ tokensRecovered,
20
+ };
21
+
22
+ // Store for display (expires after 60s — only show briefly after compact)
23
+ writeCache(RESUME_KEY, info, cacheDir);
24
+ return info;
25
+ }
26
+
27
+ export function getResumeInfo(cacheDir: string): ResumeInfo | null {
28
+ return readCache<ResumeInfo>(RESUME_KEY, 60000, cacheDir);
29
+ }
30
+
4
31
  export interface PromptStats {
5
32
  count: number;
6
33
  avgTokens: number;
package/src/types.ts CHANGED
@@ -5,6 +5,7 @@ import type { McpServerInfo } from './mcp-monitor.js';
5
5
  import type { Locale } from './i18n.js';
6
6
  import type { CustomWidget } from './custom-widgets.js';
7
7
  import type { Suggestion } from './suggestions.js';
8
+ import type { ResumeInfo } from './session-stats.js';
8
9
 
9
10
  export interface StdinData {
10
11
  transcript_path?: string;
@@ -153,4 +154,5 @@ export interface RenderContext {
153
154
  customWidgets: CustomWidget[];
154
155
  suggestions: Suggestion[];
155
156
  rateLimitEta: string | null;
157
+ resumeInfo: ResumeInfo | null;
156
158
  }