exe-watcher 0.2.12 → 0.2.13

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/dist/cli.js CHANGED
@@ -1660,7 +1660,8 @@ function emptyEntry(date) {
1660
1660
  oneShotTurns: 0,
1661
1661
  models: {},
1662
1662
  categories: {},
1663
- providers: {}
1663
+ providers: {},
1664
+ projects: {}
1664
1665
  };
1665
1666
  }
1666
1667
  function emptyProviderBreakdown() {
@@ -1700,10 +1701,20 @@ function aggregateProjectsIntoDays(projects) {
1700
1701
  }
1701
1702
  return breakdown;
1702
1703
  };
1704
+ const ensureProject = (date, projectName) => {
1705
+ const day = ensure(date);
1706
+ let project = day.projects[projectName];
1707
+ if (!project) {
1708
+ project = { cost: 0, sessions: 0 };
1709
+ day.projects[projectName] = project;
1710
+ }
1711
+ return project;
1712
+ };
1703
1713
  for (const project of projects) {
1704
1714
  for (const session of project.sessions) {
1705
1715
  const sessionDate = dateKey(session.firstTimestamp);
1706
1716
  ensure(sessionDate).sessions += 1;
1717
+ ensureProject(sessionDate, project.project).sessions += 1;
1707
1718
  const providersSeenInSession = /* @__PURE__ */ new Set();
1708
1719
  for (const turn of session.turns) {
1709
1720
  if (turn.assistantCalls.length === 0) continue;
@@ -1748,6 +1759,7 @@ function aggregateProjectsIntoDays(projects) {
1748
1759
  model.cacheReadTokens += call.usage.cacheReadInputTokens;
1749
1760
  model.cacheWriteTokens += call.usage.cacheCreationInputTokens;
1750
1761
  callDay.models[call.model] = model;
1762
+ ensureProject(callDate, project.project).cost += call.costUSD;
1751
1763
  }
1752
1764
  for (const [provider, calls] of callsByProvider) {
1753
1765
  providersSeenInSession.add(provider);
@@ -3670,31 +3682,35 @@ function estimateAgentCosts(stats) {
3670
3682
  }))
3671
3683
  };
3672
3684
  }
3673
- function buildProjectSpend(projects24h, projects7d, projects30d) {
3674
- const aggregate = (projects) => {
3685
+ function buildProjectSpendFromDays(selectedDays, days24h, days7d, days30d) {
3686
+ const aggregate = (days) => {
3675
3687
  const byName = {};
3676
- for (const p of projects) {
3677
- const name = cleanProjectName(p.project);
3678
- if (!byName[name]) byName[name] = { cost: 0, sessions: 0 };
3679
- byName[name].cost += p.totalCostUSD;
3680
- byName[name].sessions += p.sessions.length;
3688
+ for (const day of days) {
3689
+ for (const [projectName, totals] of Object.entries(day.projects)) {
3690
+ const name = cleanProjectName(projectName);
3691
+ if (!byName[name]) byName[name] = { cost: 0, sessions: 0 };
3692
+ byName[name].cost += totals.cost;
3693
+ byName[name].sessions += totals.sessions;
3694
+ }
3681
3695
  }
3682
3696
  return byName;
3683
3697
  };
3684
- const d24 = aggregate(projects24h);
3685
- const d7 = aggregate(projects7d);
3686
- const d30 = aggregate(projects30d);
3687
- const allNames = /* @__PURE__ */ new Set([...Object.keys(d24), ...Object.keys(d7), ...Object.keys(d30)]);
3698
+ const selected = aggregate(selectedDays);
3699
+ const d24 = aggregate(days24h);
3700
+ const d7 = aggregate(days7d);
3701
+ const d30 = aggregate(days30d);
3702
+ const allNames = /* @__PURE__ */ new Set([...Object.keys(selected), ...Object.keys(d24), ...Object.keys(d7), ...Object.keys(d30)]);
3688
3703
  return Array.from(allNames).map((name) => ({
3689
3704
  name,
3690
3705
  cost24h: d24[name]?.cost ?? 0,
3691
3706
  cost7d: d7[name]?.cost ?? 0,
3692
3707
  cost30d: d30[name]?.cost ?? 0,
3693
- sessions: d30[name]?.sessions ?? d7[name]?.sessions ?? d24[name]?.sessions ?? 0
3694
- })).filter((d) => d.cost30d > 0 || d.cost7d > 0 || d.cost24h > 0).sort((a, b) => b.cost30d - a.cost30d);
3708
+ selectedPeriodCost: selected[name]?.cost ?? 0,
3709
+ sessions: selected[name]?.sessions ?? d30[name]?.sessions ?? d7[name]?.sessions ?? d24[name]?.sessions ?? 0
3710
+ })).filter((d) => d.selectedPeriodCost > 0).sort((a, b) => b.selectedPeriodCost - a.selectedPeriodCost);
3695
3711
  }
3696
3712
  function cleanProjectName(dirName) {
3697
- const base = dirName.replace(/--worktrees-.*$/, "");
3713
+ const base = dirName.replace(/--worktrees-.*$/, "").replace(/-\.worktrees-.*/, "").replace(/\/\.worktrees\/.*/, "");
3698
3714
  const parts = base.split("-");
3699
3715
  const usersIdx = parts.indexOf("Users");
3700
3716
  if (usersIdx >= 0 && usersIdx + 2 < parts.length) {
@@ -3795,7 +3811,7 @@ import { createHash as createHash3, randomBytes as randomBytes5 } from "crypto";
3795
3811
  import { existsSync as existsSync3 } from "fs";
3796
3812
  import { mkdir as mkdir7, open as open5, readFile as readFile7, rename as rename6, unlink as unlink3 } from "fs/promises";
3797
3813
  import { join as join16 } from "path";
3798
- var DAILY_CACHE_VERSION = 4;
3814
+ var DAILY_CACHE_VERSION = 5;
3799
3815
  var DEFAULT_DAILY_CACHE_SCOPE = "global";
3800
3816
  var DAILY_CACHE_FILENAME = "daily-cache.json";
3801
3817
  function getCachePath3(scopeKey) {
@@ -7134,17 +7150,18 @@ program.command("status").description("Compact status output (today + week + mon
7134
7150
  const parseTimeMs = Date.now() - parseStart;
7135
7151
  const todayDays = aggregateProjectsIntoDays(todayProjects);
7136
7152
  let daysCount = 0;
7153
+ let selectedPeriodDays = [];
7137
7154
  {
7138
7155
  const rangeStartStr = toDateString(periodInfo.range.start);
7139
7156
  const rangeEndStr = toDateString(periodInfo.range.end);
7140
7157
  const historicalDays = getDaysInRange(cache, rangeStartStr, yesterdayStr);
7141
7158
  const todayOnly = todayDays.filter((d) => d.date > yesterdayStr && d.date <= rangeEndStr);
7142
- const allDays = [...historicalDays, ...todayOnly].sort((a, b) => a.date.localeCompare(b.date));
7143
- daysCount = allDays.length;
7159
+ selectedPeriodDays = [...historicalDays, ...todayOnly].sort((a, b) => a.date.localeCompare(b.date));
7160
+ daysCount = selectedPeriodDays.length;
7144
7161
  if (isAllProviders) {
7145
- currentData = buildPeriodDataFromDays(allDays, periodInfo.label);
7162
+ currentData = buildPeriodDataFromDays(selectedPeriodDays, periodInfo.label);
7146
7163
  } else {
7147
- const providerDays = filterDaysToProvider(allDays, pf);
7164
+ const providerDays = filterDaysToProvider(selectedPeriodDays, pf);
7148
7165
  currentData = buildPeriodDataFromDays(providerDays, periodInfo.label);
7149
7166
  }
7150
7167
  }
@@ -7257,19 +7274,21 @@ program.command("status").description("Compact status output (today + week + mon
7257
7274
  }
7258
7275
  let projectSpend = null;
7259
7276
  try {
7260
- const [proj7d, proj30d] = await Promise.all([
7261
- Promise.race([
7262
- parseAllSessions(getDateRange2("week").range, "all"),
7263
- new Promise((r) => setTimeout(() => r([]), 500))
7264
- ]),
7265
- Promise.race([
7266
- parseAllSessions(getDateRange2("30days").range, "all"),
7267
- new Promise((r) => setTimeout(() => r([]), 500))
7268
- ])
7269
- ]);
7270
- projectSpend = buildProjectSpend(allTodayProjects, proj7d, proj30d);
7277
+ const weekStartStr = toDateString(getDateRange2("week").range.start);
7278
+ const thirtyDayStartStr = toDateString(getDateRange2("30days").range.start);
7279
+ const todayOnlyDays = todayDays.filter((d) => d.date > yesterdayStr);
7280
+ const days7d = [
7281
+ ...getDaysInRange(cache, weekStartStr, yesterdayStr),
7282
+ ...todayOnlyDays
7283
+ ].sort((a, b) => a.date.localeCompare(b.date));
7284
+ const days30d = [
7285
+ ...getDaysInRange(cache, thirtyDayStartStr, yesterdayStr),
7286
+ ...todayOnlyDays
7287
+ ].sort((a, b) => a.date.localeCompare(b.date));
7288
+ projectSpend = buildProjectSpendFromDays(selectedPeriodDays, todayOnlyDays, days7d, days30d);
7271
7289
  } catch {
7272
- projectSpend = buildProjectSpend(allTodayProjects, [], []);
7290
+ const todayOnlyDays = todayDays.filter((d) => d.date > yesterdayStr);
7291
+ projectSpend = buildProjectSpendFromDays(selectedPeriodDays, todayOnlyDays, [], []);
7273
7292
  }
7274
7293
  const diagnostics = { daysCount, parseTimeMs, warnings };
7275
7294
  const payload = buildMenubarPayload(currentData, providers, optimize, dailyHistory, agentStats, projectSpend, exeOsDetected, statsFileAge, diagnostics);
@@ -7569,7 +7588,7 @@ program.command("plan [action] [id]").description("Show or configure a subscript
7569
7588
  console.log(` Config saved to ${getConfigFilePath()}
7570
7589
  `);
7571
7590
  });
7572
- program.command("optimize").description("Find token waste and get exact fixes").option("-p, --period <period>", "Analysis period: today, week, 30days, month, all", "30days").option("--provider <provider>", "Filter by provider: all, claude, codex, cursor", "all").action(async (opts) => {
7591
+ program.command("optimize").description("Find token waste and get exact fixes").option("-p, --period <period>", "Analysis period: today, week, 30days, month, all", "week").option("--provider <provider>", "Filter by provider: all, claude, codex, cursor", "all").action(async (opts) => {
7573
7592
  await loadPricing();
7574
7593
  const { range, label } = getDateRange2(opts.period);
7575
7594
  const scanPromise = prewarmOptimizeScan(range);