fleetlens 0.9.0 → 0.10.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 (130) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/build-manifest.json +3 -3
  3. package/app/apps/web/.next/prerender-manifest.json +3 -3
  4. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  5. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  6. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  12. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/app/apps/web/.next/server/app/api/ask/route.js +1 -1
  14. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  15. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +3 -3
  16. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  17. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +3 -3
  18. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/api/digest/month-index/route.js +2 -2
  20. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +3 -3
  22. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  23. package/app/apps/web/.next/server/app/api/digest/week-index/route.js +2 -2
  24. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  25. package/app/apps/web/.next/server/app/api/events/route.js +1 -1
  26. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  27. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  29. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/settings/route.js +4 -4
  31. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  34. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  35. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  36. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  37. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  38. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  39. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  40. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  41. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  42. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  44. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  45. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  46. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  47. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  48. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  49. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  50. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  51. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  52. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  53. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  54. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  55. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  56. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  57. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  58. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  59. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  60. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  61. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  62. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  63. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  64. package/app/apps/web/.next/server/chunks/[root-of-the-server]__07qxzx4._.js +9 -0
  65. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0fu2xfy._.js +5 -0
  66. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0gfd42k._.js +9 -0
  67. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0i.m8y0._.js +3 -0
  68. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0iy5aqy._.js +9 -0
  69. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0nh7-nf._.js +3 -0
  70. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0nvdffv._.js +3 -0
  71. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0s2~c3g._.js +3 -0
  72. package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0ck.78s.js +3 -3
  73. package/app/apps/web/.next/server/chunks/packages_09wmnv.._.js +3 -0
  74. package/app/apps/web/.next/server/chunks/packages_0o6.gpk._.js +3 -0
  75. package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +13 -13
  76. package/app/apps/web/.next/server/chunks/packages_parser_dist_fs_122oe0-.js +1 -1
  77. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0d~2~le._.js +1 -1
  78. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +1 -1
  79. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0s4dg1y._.js +3 -0
  80. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0tejjy_._.js +1 -1
  81. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +3 -3
  82. package/app/apps/web/.next/server/chunks/ssr/_0jw2sm7._.js +1 -1
  83. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  84. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +1 -1
  85. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +1 -1
  86. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_usage-charts-dashboard_tsx_0bgr_uv._.js +1 -1
  87. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0m67-xi._.js +1 -1
  88. package/app/apps/web/.next/server/chunks/ssr/packages_entries_dist_node_0_271yr.js +1 -1
  89. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_10_oegc._.js +1 -1
  90. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  91. package/app/apps/web/.next/server/pages/500.html +1 -1
  92. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  93. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  94. package/app/apps/web/.next/static/chunks/04a36uhu~p_z-.css +1 -0
  95. package/app/apps/web/.next/static/chunks/{0q2vd~aj.1hpz.js → 09--oejbzw3q-.js} +3 -3
  96. package/app/apps/web/.next/static/chunks/0l3ck.awv~4t7.js +1 -0
  97. package/app/apps/web/.next/static/chunks/{171za22fv684..js → 0lxuac2v0_gdl.js} +2 -2
  98. package/app/apps/web/.next/static/chunks/0n0n.0279ot6c.js +1 -0
  99. package/app/apps/web/.next/static/chunks/0qcu452dr~edz.js +14 -0
  100. package/app/apps/web/.next/static/chunks/0uev~g~qvbjv9.js +4 -0
  101. package/app/apps/web/components/previous-cycles-trend.tsx +26 -11
  102. package/app/apps/web/components/usage-chart.tsx +35 -37
  103. package/app/apps/web/components/usage-gauges.tsx +18 -12
  104. package/app/apps/web/components/usage-sidebar.tsx +23 -12
  105. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  106. package/app/apps/web/lib/utilization-tone.ts +74 -0
  107. package/app/apps/web/package.json +1 -1
  108. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  109. package/dist/daemon-worker.js +133 -31
  110. package/dist/index.js +988 -887
  111. package/package.json +1 -1
  112. package/app/apps/web/.next/server/chunks/[externals]__0fpbr8-._.js +0 -3
  113. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0-vgrh1._.js +0 -3
  114. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0.z48ue._.js +0 -3
  115. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0_8zh-i._.js +0 -9
  116. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0dctov1._.js +0 -5
  117. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e8n_x4._.js +0 -3
  118. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0ej_p3s._.js +0 -9
  119. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0jprdks._.js +0 -9
  120. package/app/apps/web/.next/server/chunks/packages_09hmrqx._.js +0 -3
  121. package/app/apps/web/.next/server/chunks/packages_118y1lp._.js +0 -3
  122. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ytdqxt._.js +0 -3
  123. package/app/apps/web/.next/static/chunks/05m.oz3kmf1p7.js +0 -1
  124. package/app/apps/web/.next/static/chunks/07-fq4im3pmjp.js +0 -4
  125. package/app/apps/web/.next/static/chunks/0cxyt4-24..b7.js +0 -14
  126. package/app/apps/web/.next/static/chunks/0o9ayt8sknubd.js +0 -1
  127. package/app/apps/web/.next/static/chunks/0wfbj5zr~az.z.css +0 -1
  128. /package/app/apps/web/.next/static/{u6-8f8u1tspYCacGAz53R → L0Dy1hOQrZjV9l0TNulvk}/_buildManifest.js +0 -0
  129. /package/app/apps/web/.next/static/{u6-8f8u1tspYCacGAz53R → L0Dy1hOQrZjV9l0TNulvk}/_clientMiddlewareManifest.js +0 -0
  130. /package/app/apps/web/.next/static/{u6-8f8u1tspYCacGAz53R → L0Dy1hOQrZjV9l0TNulvk}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -187,6 +187,14 @@ function latestSnapshot(filePath) {
187
187
  const all = readSnapshots(filePath);
188
188
  return all.length > 0 ? all[all.length - 1] : null;
189
189
  }
190
+ function latestClaudeCodeSnapshot(filePath) {
191
+ const all = readSnapshots(filePath);
192
+ for (let i = all.length - 1; i >= 0; i--) {
193
+ const s = all[i];
194
+ if (!s.agent || s.agent === "claude-code") return s;
195
+ }
196
+ return null;
197
+ }
190
198
  var init_storage = __esm({
191
199
  "src/usage/storage.ts"() {
192
200
  "use strict";
@@ -454,9 +462,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
454
462
  console.warn(
455
463
  ` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
456
464
  );
457
- } else if (verify.installedVersion !== "0.9.0") {
465
+ } else if (verify.installedVersion !== "0.10.0") {
458
466
  console.log(
459
- ` \u2192 This process is still running ${"0.9.0"}. Next invocation will use ${verify.installedVersion}.`
467
+ ` \u2192 This process is still running ${"0.10.0"}. Next invocation will use ${verify.installedVersion}.`
460
468
  );
461
469
  }
462
470
  }
@@ -492,7 +500,7 @@ async function checkForUpdate() {
492
500
  if (process.env.__FLEETLENS_UPDATED === "1" || process.env.__CCLENS_UPDATED === "1") return;
493
501
  const latest = await fetchLatestVersion();
494
502
  if (latest === null) return;
495
- const current = "0.9.0";
503
+ const current = "0.10.0";
496
504
  if (!shouldUpdate(current, latest)) return;
497
505
  console.log(`Updating ${PACKAGE_NAME} ${current} \u2192 ${latest}...`);
498
506
  await stopRunningServices();
@@ -574,7 +582,7 @@ async function restartServices(state) {
574
582
  }
575
583
  async function forceUpdate() {
576
584
  const latest = await fetchLatestVersion();
577
- const current = "0.9.0";
585
+ const current = "0.10.0";
578
586
  if (latest === null) {
579
587
  console.error("Could not reach npm registry. Check your network.");
580
588
  process.exit(1);
@@ -1050,21 +1058,37 @@ function findWorktreeMarker(projectName) {
1050
1058
  }
1051
1059
  return null;
1052
1060
  }
1061
+ function findConductorWorkspace(projectName) {
1062
+ const m = CONDUCTOR_RE.exec(projectName);
1063
+ if (!m)
1064
+ return null;
1065
+ const workspaceName = m[1];
1066
+ const trailingSlash = m[0].endsWith("/") ? 1 : 0;
1067
+ const canonicalEndIdx = m.index + m[0].length - workspaceName.length - 1 - trailingSlash;
1068
+ return { canonicalEndIdx, workspaceName };
1069
+ }
1053
1070
  function canonicalProjectName(projectName) {
1054
1071
  const normalized = projectName.replace(/\/{2,}/g, "/");
1055
- const hit = findWorktreeMarker(normalized);
1056
- if (hit)
1057
- return normalized.slice(0, hit.idx);
1072
+ const wt = findWorktreeMarker(normalized);
1073
+ if (wt)
1074
+ return normalized.slice(0, wt.idx);
1075
+ const cd = findConductorWorkspace(normalized);
1076
+ if (cd)
1077
+ return normalized.slice(0, cd.canonicalEndIdx);
1058
1078
  return normalized;
1059
1079
  }
1060
1080
  function worktreeName(projectName) {
1061
1081
  const normalized = projectName.replace(/\/{2,}/g, "/");
1062
- const hit = findWorktreeMarker(normalized);
1063
- if (!hit)
1064
- return null;
1065
- const tail = normalized.slice(hit.idx + hit.marker.length);
1066
- const slash = tail.indexOf("/");
1067
- return slash >= 0 ? tail.slice(0, slash) : tail;
1082
+ const wt = findWorktreeMarker(normalized);
1083
+ if (wt) {
1084
+ const tail = normalized.slice(wt.idx + wt.marker.length);
1085
+ const slash = tail.indexOf("/");
1086
+ return slash >= 0 ? tail.slice(0, slash) : tail;
1087
+ }
1088
+ const cd = findConductorWorkspace(normalized);
1089
+ if (cd)
1090
+ return cd.workspaceName;
1091
+ return null;
1068
1092
  }
1069
1093
  function makeDay(date) {
1070
1094
  return {
@@ -1533,7 +1557,7 @@ function groupByProject(sessions) {
1533
1557
  }
1534
1558
  return Array.from(map.values()).sort((a, b) => (b.lastActiveMs ?? 0) - (a.lastActiveMs ?? 0));
1535
1559
  }
1536
- var BLANK_USAGE, WORKTREE_MARKERS, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
1560
+ var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
1537
1561
  var init_analytics = __esm({
1538
1562
  "../parser/dist/analytics.js"() {
1539
1563
  "use strict";
@@ -1543,6 +1567,7 @@ var init_analytics = __esm({
1543
1567
  "/.worktrees/",
1544
1568
  "/claude/worktrees/"
1545
1569
  ];
1570
+ CONDUCTOR_RE = /\/conductor\/workspaces\/[^/]+\/([^/]+)(?:\/|$)/;
1546
1571
  PR_CREATE_RE = /gh\s+pr\s+create\b/i;
1547
1572
  PR_NUMBER_RE = /#(\d+)/;
1548
1573
  TITLE_FLAG_RE = /--title\s+["']([^"']+)["']/;
@@ -1775,10 +1800,64 @@ var init_calibration = __esm({
1775
1800
  }
1776
1801
  });
1777
1802
 
1803
+ // ../parser/dist/user-input.js
1804
+ function stripFrameworkBoilerplate(rawText) {
1805
+ if (!rawText)
1806
+ return rawText;
1807
+ let out = rawText;
1808
+ for (const re of STRIPPABLE_WRAPPERS) {
1809
+ out = out.replace(re, "");
1810
+ }
1811
+ return out.trim();
1812
+ }
1813
+ function isFrameworkInjectedUserInput(rawText) {
1814
+ if (!rawText)
1815
+ return false;
1816
+ const stripped = stripFrameworkBoilerplate(rawText);
1817
+ if (!stripped)
1818
+ return true;
1819
+ for (const prefix of ENTIRELY_INJECTED_PREFIXES) {
1820
+ if (stripped.startsWith(prefix))
1821
+ return true;
1822
+ }
1823
+ return false;
1824
+ }
1825
+ var STRIPPABLE_WRAPPERS, ENTIRELY_INJECTED_PREFIXES;
1826
+ var init_user_input = __esm({
1827
+ "../parser/dist/user-input.js"() {
1828
+ "use strict";
1829
+ STRIPPABLE_WRAPPERS = [
1830
+ /<system_instruction\b[^>]*>[\s\S]*?<\/system_instruction>\s*/gi
1831
+ ];
1832
+ ENTIRELY_INJECTED_PREFIXES = [
1833
+ "<command-name>",
1834
+ "<local-command-stdout>",
1835
+ "<local-command-caveat>",
1836
+ "<task-notification>",
1837
+ "Base directory for this skill:"
1838
+ ];
1839
+ }
1840
+ });
1841
+
1778
1842
  // ../parser/dist/parser.js
1779
1843
  function cleanText(s) {
1780
1844
  return s.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
1781
1845
  }
1846
+ function extractRawUserText(rawMsg) {
1847
+ const c = rawMsg?.content;
1848
+ if (typeof c === "string")
1849
+ return c;
1850
+ if (Array.isArray(c)) {
1851
+ for (const block of c) {
1852
+ if (block && typeof block === "object") {
1853
+ const b = block;
1854
+ if (b.type === "text" && typeof b.text === "string")
1855
+ return b.text;
1856
+ }
1857
+ }
1858
+ }
1859
+ return "";
1860
+ }
1782
1861
  function truncate(s, n = 200) {
1783
1862
  const one = cleanText(s);
1784
1863
  return one.length > n ? one.slice(0, n - 1) + "\u2026" : one;
@@ -1877,7 +1956,8 @@ function toEvent(raw, index) {
1877
1956
  const msg = r.message ?? {};
1878
1957
  const c = msg.content;
1879
1958
  if (typeof c === "string") {
1880
- const tm = classifyTeammateMessage(c);
1959
+ const cleaned = stripFrameworkBoilerplate(c);
1960
+ const tm = classifyTeammateMessage(cleaned);
1881
1961
  return {
1882
1962
  index,
1883
1963
  uuid,
@@ -1885,8 +1965,8 @@ function toEvent(raw, index) {
1885
1965
  timestamp,
1886
1966
  role: "user",
1887
1967
  rawType,
1888
- preview: truncate(c, 200),
1889
- blocks: [{ type: "text", text: c }],
1968
+ preview: truncate(cleaned, 200),
1969
+ blocks: cleaned ? [{ type: "text", text: cleaned }] : [],
1890
1970
  raw,
1891
1971
  teammateMessage: tm
1892
1972
  };
@@ -1910,7 +1990,9 @@ function toEvent(raw, index) {
1910
1990
  };
1911
1991
  }
1912
1992
  const textBlock = c.find((b) => b?.type === "text");
1913
- const tm = textBlock ? classifyTeammateMessage(textBlock.text) : void 0;
1993
+ const cleanedText = textBlock ? stripFrameworkBoilerplate(textBlock.text) : "";
1994
+ const cleanedBlocks = textBlock ? c.map((b) => b === textBlock ? { type: "text", text: cleanedText } : b) : c;
1995
+ const tm = cleanedText ? classifyTeammateMessage(cleanedText) : void 0;
1914
1996
  return {
1915
1997
  index,
1916
1998
  uuid,
@@ -1918,8 +2000,8 @@ function toEvent(raw, index) {
1918
2000
  timestamp,
1919
2001
  role: "user",
1920
2002
  rawType,
1921
- preview: textBlock ? truncate(textBlock.text, 200) : truncate(JSON.stringify(c), 200),
1922
- blocks: c,
2003
+ preview: cleanedText ? truncate(cleanedText, 200) : truncate(JSON.stringify(c), 200),
2004
+ blocks: cleanedBlocks,
1923
2005
  raw,
1924
2006
  teammateMessage: tm
1925
2007
  };
@@ -2139,8 +2221,8 @@ function parseTranscript(rawLines) {
2139
2221
  }
2140
2222
  if (e.role === "user") {
2141
2223
  const rawMsg = e.raw?.message;
2142
- const rawContent = typeof rawMsg?.content === "string" ? rawMsg.content : "";
2143
- const isHidden = rawContent.startsWith("<command-name>") || rawContent.startsWith("<local-command-caveat>") || rawContent.startsWith("Base directory for this skill:") || rawContent.startsWith("<task-notification>");
2224
+ const rawContent = extractRawUserText(rawMsg);
2225
+ const isHidden = isFrameworkInjectedUserInput(rawContent);
2144
2226
  const isTeamNoise = e.teammateMessage !== void 0 && !agentName;
2145
2227
  if (!isHidden && !isTeamNoise) {
2146
2228
  if (!firstUserPreview) {
@@ -2225,6 +2307,7 @@ var BLANK_USAGE2, TEAMMATE_MSG_RE;
2225
2307
  var init_parser = __esm({
2226
2308
  "../parser/dist/parser.js"() {
2227
2309
  "use strict";
2310
+ init_user_input();
2228
2311
  BLANK_USAGE2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
2229
2312
  TEAMMATE_MSG_RE = /^\s*<teammate-message\s+teammate_id="([^"]+)"[^>]*>([\s\S]*?)<\/teammate-message>/;
2230
2313
  }
@@ -3043,7 +3126,8 @@ function parseRollout(file, lines) {
3043
3126
  if (type === "event_msg" && subtype === "user_message") {
3044
3127
  const text = typeof payload.message === "string" ? payload.message : "";
3045
3128
  const preview = previewOf(text);
3046
- if (text) {
3129
+ const isHidden = isFrameworkInjectedUserInput(text);
3130
+ if (text && !isHidden) {
3047
3131
  if (!firstUserPreview)
3048
3132
  firstUserPreview = preview;
3049
3133
  lastUserPreview = preview;
@@ -3360,6 +3444,7 @@ var init_codex = __esm({
3360
3444
  "../parser/dist/codex.js"() {
3361
3445
  "use strict";
3362
3446
  init_analytics();
3447
+ init_user_input();
3363
3448
  DEFAULT_CODEX_ROOT = path2.join(os2.homedir(), ".codex", "sessions");
3364
3449
  ROLLOUT_RE = /^rollout-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})-([0-9a-f-]+)\.jsonl$/;
3365
3450
  IDLE_GAP_MS = 3 * 60 * 1e3;
@@ -3582,7 +3667,8 @@ async function parseSession(file) {
3582
3667
  if (msg.type === "user") {
3583
3668
  const text = flattenContent(msg.displayContent ?? msg.content);
3584
3669
  const preview = previewOf2(text);
3585
- if (text) {
3670
+ const isHidden = isFrameworkInjectedUserInput(text);
3671
+ if (text && !isHidden) {
3586
3672
  if (!firstUserPreview)
3587
3673
  firstUserPreview = preview;
3588
3674
  lastUserPreview = preview;
@@ -3857,6 +3943,7 @@ var init_gemini = __esm({
3857
3943
  "../parser/dist/gemini.js"() {
3858
3944
  "use strict";
3859
3945
  init_analytics();
3946
+ init_user_input();
3860
3947
  DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
3861
3948
  GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
3862
3949
  SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
@@ -4510,138 +4597,612 @@ var init_types = __esm({
4510
4597
  }
4511
4598
  });
4512
4599
 
4513
- // ../entries/dist/signals.js
4514
- function classifyUserInputSource(text) {
4515
- if (!text)
4516
- return "human";
4517
- if (TEAMMATE_RE.test(text))
4518
- return "teammate";
4519
- if (SKILL_LOAD_RE.test(text))
4520
- return "skill_load";
4521
- if (SLASH_COMMAND_RE.test(text))
4522
- return "slash_command";
4523
- return "human";
4524
- }
4525
- function classifySubagentRole(sa) {
4526
- const text = `${sa.description} ${sa.prompt_preview}`.toLowerCase();
4527
- if (/\b(re-?review|review[s]?|verify|audit|spec[- ]review|code[- ]quality|code[- ]reuse|efficiency review|sanity check|quick test)\b/.test(text)) {
4528
- return "reviewer";
4529
- }
4530
- if (/\b(implement|build chunk|build task|initialize|create the|add the)\b/.test(text)) {
4531
- return "implementer";
4532
- }
4533
- if (/\bexplore\b|\binventory\b|\bmap\b.*\b(codebase|repo|branch)\b|\baudit\b.*coverage/.test(text)) {
4534
- return "explorer";
4535
- }
4536
- if (/\b(investigate|research|reverse[- ]engineer|study|analy[sz]e|look up|tell me|brief me on|find out)\b/.test(text)) {
4537
- return "researcher";
4538
- }
4539
- if (/\b(env(?:ironment)? setup|configure|setup|bootstrap)\b/.test(text)) {
4540
- return "env-setup";
4541
- }
4542
- if (/\b(polish|cleanup|fix|refactor)\b/.test(text)) {
4543
- return "polish";
4600
+ // ../parser/dist/types.js
4601
+ var init_types2 = __esm({
4602
+ "../parser/dist/types.js"() {
4603
+ "use strict";
4544
4604
  }
4545
- return "other";
4546
- }
4547
- function isStockSubagentType(type) {
4548
- return STOCK_SUBAGENT_PREFIXES.test(type);
4605
+ });
4606
+
4607
+ // ../parser/dist/presentation.js
4608
+ function rowPrimaryIndex(r) {
4609
+ if (r.kind === "tool-group")
4610
+ return r.events[0].index;
4611
+ return r.event.index;
4549
4612
  }
4550
- function inferWorkingShape(entry) {
4551
- if (entry.numbers.turn_count < 2)
4552
- return null;
4553
- const subagents = entry.subagents ?? [];
4554
- const roles = subagents.map(classifySubagentRole);
4555
- const reviewerCount = roles.filter((r) => r === "reviewer").length;
4556
- const implementerCount = roles.filter((r) => r === "implementer").length;
4557
- const explorerOrResearcher = roles.filter((r) => r === "explorer" || r === "researcher").length;
4558
- const hasBackground = subagents.some((sa) => sa.background);
4559
- if (implementerCount >= 2) {
4560
- const chunkRefs = subagents.filter((sa) => /\b(chunk|task)\s*\d+/i.test(`${sa.description} ${sa.prompt_preview}`));
4561
- if (chunkRefs.length >= 2)
4562
- return "chunk-implementation";
4563
- }
4564
- if (reviewerCount >= 3 && implementerCount === 0) {
4565
- const lensSigs = /* @__PURE__ */ new Set();
4566
- for (let i = 0; i < subagents.length; i++) {
4567
- if (roles[i] !== "reviewer")
4613
+ function buildMegaRows(rows) {
4614
+ const out = [];
4615
+ let buffer = [];
4616
+ const flush = () => {
4617
+ if (buffer.length === 0)
4618
+ return;
4619
+ let agentMessages = 0;
4620
+ let toolCalls = 0;
4621
+ let errors = 0;
4622
+ let firstAgentIndex;
4623
+ const toolMap = /* @__PURE__ */ new Map();
4624
+ const seenMsgIds = /* @__PURE__ */ new Set();
4625
+ const tokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
4626
+ for (let i = 0; i < buffer.length; i++) {
4627
+ const r = buffer[i];
4628
+ if (r.kind === "agent") {
4629
+ agentMessages++;
4630
+ if (firstAgentIndex === void 0)
4631
+ firstAgentIndex = i;
4632
+ const msgId = r.event.messageId;
4633
+ const usage2 = r.event.usage;
4634
+ if (msgId && !seenMsgIds.has(msgId) && usage2) {
4635
+ seenMsgIds.add(msgId);
4636
+ tokens.input += usage2.input;
4637
+ tokens.output += usage2.output;
4638
+ tokens.cacheRead += usage2.cacheRead;
4639
+ tokens.cacheWrite += usage2.cacheWrite;
4640
+ }
4641
+ } else if (r.kind === "tool-group") {
4642
+ toolCalls += r.count;
4643
+ for (const t of r.toolNames) {
4644
+ toolMap.set(t.name, (toolMap.get(t.name) ?? 0) + t.count);
4645
+ }
4646
+ } else if (r.kind === "error") {
4647
+ errors++;
4648
+ }
4649
+ }
4650
+ let finalAgentIndex;
4651
+ for (let i = buffer.length - 1; i >= 0; i--) {
4652
+ const r = buffer[i];
4653
+ if (r.kind !== "agent")
4568
4654
  continue;
4569
- const sig = subagents[i].description.toLowerCase().replace(/[^a-z0-9 ]/g, "").split(/\s+/).filter((w) => w.length > 2).slice(0, 3).join("|");
4570
- lensSigs.add(sig);
4655
+ const prev = buffer[i - 1];
4656
+ if (prev?.kind === "task-notification")
4657
+ continue;
4658
+ finalAgentIndex = i;
4659
+ break;
4660
+ }
4661
+ if (finalAgentIndex === void 0) {
4662
+ for (let i = buffer.length - 1; i >= 0; i--) {
4663
+ if (buffer[i].kind === "agent") {
4664
+ finalAgentIndex = i;
4665
+ break;
4666
+ }
4667
+ }
4668
+ }
4669
+ const firstAgentPreview = firstAgentIndex !== void 0 && buffer[firstAgentIndex].kind === "agent" ? buffer[firstAgentIndex].event.preview : void 0;
4670
+ const finalAgentPreview = finalAgentIndex !== void 0 && buffer[finalAgentIndex].kind === "agent" ? buffer[finalAgentIndex].event.preview : void 0;
4671
+ const toolNames = Array.from(toolMap.entries()).sort((a, b) => b[1] - a[1]).map(([name, count]) => ({ name, count }));
4672
+ const first = buffer[0];
4673
+ const last = buffer[buffer.length - 1];
4674
+ const start2 = first.tOffsetMs;
4675
+ const end = last.tOffsetMs;
4676
+ const durationMs = start2 !== void 0 && end !== void 0 ? end - start2 : void 0;
4677
+ out.push({
4678
+ kind: "turn",
4679
+ rows: buffer,
4680
+ firstPrimaryIndex: rowPrimaryIndex(first),
4681
+ tOffsetMs: start2,
4682
+ durationMs,
4683
+ summary: {
4684
+ agentMessages,
4685
+ toolCalls,
4686
+ errors,
4687
+ firstAgentPreview,
4688
+ finalAgentPreview,
4689
+ firstAgentIndex,
4690
+ finalAgentIndex,
4691
+ toolNames,
4692
+ totalTokens: tokens
4693
+ }
4694
+ });
4695
+ buffer = [];
4696
+ };
4697
+ for (const r of rows) {
4698
+ if (r.kind === "user" || r.kind === "interrupt") {
4699
+ flush();
4700
+ out.push(r);
4701
+ } else {
4702
+ buffer.push(r);
4571
4703
  }
4572
- if (lensSigs.size >= 3)
4573
- return "reviewer-triad";
4574
- }
4575
- if (reviewerCount >= 2)
4576
- return "spec-review-loop";
4577
- if (explorerOrResearcher >= 2 || explorerOrResearcher >= 1 && implementerCount >= 1) {
4578
- return "research-then-build";
4579
- }
4580
- if (hasBackground && subagents.length >= 1)
4581
- return "background-coordinated";
4582
- if (subagents.length === 0) {
4583
- const first = (entry.first_user || "").trim().toLowerCase();
4584
- if (/^continue\b/.test(first) || first === "continue.")
4585
- return "solo-continuation";
4586
- const skills = Object.keys(entry.skills ?? {});
4587
- if (skills.some((s) => /brainstorm|writing-plans|brainstorming/i.test(s)))
4588
- return "solo-design";
4589
- return "solo-build";
4590
- }
4591
- return "solo-build";
4592
- }
4593
- function detectPromptFrames(text) {
4594
- if (!text)
4595
- return [];
4596
- const out = [];
4597
- if (/<teammate-message\b/i.test(text))
4598
- out.push("teammate");
4599
- if (/<task-notification\b/i.test(text))
4600
- out.push("task-notification");
4601
- if (/<local-command-caveat\b/i.test(text))
4602
- out.push("local-command-caveat");
4603
- if (/<command-(message|name)\b/i.test(text))
4604
- out.push("slash-command");
4605
- if (/\[Image #\d+\]/.test(text))
4606
- out.push("image-attached");
4607
- if (/\b(here'?s the (handoff|handover) prompt|session-close summary|wrap-up summary|all wrapped up|all captured\.)\b/i.test(text) || /^##? (Wrap-up|Session conclusion|Handoff)\b/m.test(text) || /^# Handoff:/m.test(text)) {
4608
- out.push("handoff-prose");
4609
4704
  }
4705
+ flush();
4610
4706
  return out;
4611
4707
  }
4612
- function classifySkill(name) {
4613
- if (name.startsWith("(ToolSearch:"))
4614
- return "infra";
4615
- if (STOCK_SKILL_PREFIXES.test(name))
4616
- return "stock";
4617
- if (name === "using-superpowers")
4618
- return "stock";
4619
- return "user";
4620
- }
4621
- function detectExternalRef(text) {
4622
- if (!text)
4623
- return null;
4624
- if (/<teammate-message|<task-notification|<local-command-caveat/i.test(text.slice(0, 400)))
4708
+ function parseTaskNotification(text) {
4709
+ if (!TASK_NOTIFICATION_RE.test(text))
4625
4710
  return null;
4626
- for (const { kind, re } of EXTERNAL_REF_PATTERNS) {
4627
- const m = text.match(re);
4628
- if (m)
4629
- return { kind, preview: text.slice(0, 160) };
4630
- }
4631
- return null;
4632
- }
4633
- function bucketVerbosity(n) {
4634
- if (n < 100)
4635
- return "short";
4636
- if (n < 500)
4637
- return "medium";
4638
- if (n < 2e3)
4639
- return "long";
4640
- return "very_long";
4641
- }
4642
- function computeEntrySignals(entry) {
4643
- const fu = entry.first_user || "";
4644
- const verbosity = bucketVerbosity(fu.length);
4711
+ const pick = (tag) => {
4712
+ const m = text.match(new RegExp(`<${tag}>([\\s\\S]*?)<\\/${tag}>`));
4713
+ return m ? m[1].trim() : void 0;
4714
+ };
4715
+ const statusRaw = (pick("status") ?? "").toLowerCase();
4716
+ let status2 = "unknown";
4717
+ if (statusRaw === "success" || statusRaw === "ok" || statusRaw === "done" || statusRaw === "completed")
4718
+ status2 = "success";
4719
+ else if (statusRaw === "failed" || statusRaw === "error" || statusRaw === "fail")
4720
+ status2 = "failed";
4721
+ else if (statusRaw === "running" || statusRaw === "in_progress")
4722
+ status2 = "running";
4723
+ return {
4724
+ status: status2,
4725
+ summary: pick("summary") ?? "Background task notification",
4726
+ taskId: pick("task-id"),
4727
+ toolUseId: pick("tool-use-id"),
4728
+ outputFile: pick("output-file")
4729
+ };
4730
+ }
4731
+ function isAttachmentOrMeta(e) {
4732
+ return e.role === "system" || e.role === "meta";
4733
+ }
4734
+ function firstTextOfBlocks(blocks) {
4735
+ for (const b of blocks) {
4736
+ if (b?.type === "text")
4737
+ return b.text;
4738
+ }
4739
+ return void 0;
4740
+ }
4741
+ function hasZeroUsage(e) {
4742
+ if (!e.usage)
4743
+ return false;
4744
+ const u = e.usage;
4745
+ return u.input === 0 && u.output === 0 && u.cacheRead === 0 && u.cacheWrite === 0;
4746
+ }
4747
+ function buildPresentation(events) {
4748
+ const byMessageId = /* @__PURE__ */ new Map();
4749
+ for (const e of events) {
4750
+ if (!e.messageId)
4751
+ continue;
4752
+ const list = byMessageId.get(e.messageId) ?? [];
4753
+ list.push(e);
4754
+ byMessageId.set(e.messageId, list);
4755
+ }
4756
+ const visible = events.filter((e) => {
4757
+ if (isAttachmentOrMeta(e))
4758
+ return false;
4759
+ if (e.role === "tool-result")
4760
+ return false;
4761
+ if (e.role === "agent-thinking")
4762
+ return false;
4763
+ if (e.role === "user") {
4764
+ const txt = firstTextOfBlocks(e.blocks) ?? "";
4765
+ if (e.blocks.length === 0 || !txt.trim())
4766
+ return false;
4767
+ if (SLASH_COMMAND_RE.test(txt))
4768
+ return true;
4769
+ if (TASK_NOTIFICATION_RE.test(txt))
4770
+ return true;
4771
+ if (isFrameworkInjectedUserInput(txt))
4772
+ return false;
4773
+ }
4774
+ return true;
4775
+ });
4776
+ const rows = [];
4777
+ for (let i = 0; i < visible.length; i++) {
4778
+ const e = visible[i];
4779
+ if (e.role === "tool-call") {
4780
+ const start2 = i;
4781
+ while (i + 1 < visible.length && visible[i + 1].role === "tool-call") {
4782
+ i++;
4783
+ }
4784
+ const group = visible.slice(start2, i + 1);
4785
+ const order = [];
4786
+ const counts = /* @__PURE__ */ new Map();
4787
+ for (const ev of group) {
4788
+ const name = ev.toolName ?? "tool";
4789
+ if (!counts.has(name))
4790
+ order.push(name);
4791
+ counts.set(name, (counts.get(name) ?? 0) + 1);
4792
+ }
4793
+ const toolNames = order.map((name) => ({
4794
+ name,
4795
+ count: counts.get(name) ?? 1
4796
+ }));
4797
+ rows.push({
4798
+ kind: "tool-group",
4799
+ toolNames,
4800
+ count: group.length,
4801
+ events: group,
4802
+ tOffsetMs: group[0].tOffsetMs,
4803
+ gapMs: group[0].gapMs
4804
+ });
4805
+ continue;
4806
+ }
4807
+ if (e.role === "user") {
4808
+ const txt = firstTextOfBlocks(e.blocks) ?? "";
4809
+ const taskNotif = parseTaskNotification(txt);
4810
+ if (taskNotif) {
4811
+ rows.push({
4812
+ kind: "task-notification",
4813
+ event: e,
4814
+ status: taskNotif.status,
4815
+ summary: taskNotif.summary,
4816
+ taskId: taskNotif.taskId,
4817
+ toolUseId: taskNotif.toolUseId,
4818
+ outputFile: taskNotif.outputFile,
4819
+ tOffsetMs: e.tOffsetMs,
4820
+ gapMs: e.gapMs
4821
+ });
4822
+ continue;
4823
+ }
4824
+ if (INTERRUPT_RE.test(txt)) {
4825
+ rows.push({
4826
+ kind: "interrupt",
4827
+ event: e,
4828
+ tOffsetMs: e.tOffsetMs,
4829
+ gapMs: e.gapMs
4830
+ });
4831
+ continue;
4832
+ }
4833
+ const slashMatch = txt.match(SLASH_COMMAND_RE);
4834
+ if (slashMatch) {
4835
+ const cmd = slashMatch[1];
4836
+ const args2 = (slashMatch[2] ?? "").trim();
4837
+ const pretty = args2 ? `${cmd} ${args2}` : cmd;
4838
+ rows.push({
4839
+ kind: "user",
4840
+ event: e,
4841
+ displayPreview: pretty,
4842
+ displayBlocks: [{ type: "text", text: pretty }],
4843
+ tOffsetMs: e.tOffsetMs,
4844
+ gapMs: e.gapMs
4845
+ });
4846
+ continue;
4847
+ }
4848
+ rows.push({
4849
+ kind: "user",
4850
+ event: e,
4851
+ tOffsetMs: e.tOffsetMs,
4852
+ gapMs: e.gapMs
4853
+ });
4854
+ continue;
4855
+ }
4856
+ if (e.role === "agent") {
4857
+ const txt = firstTextOfBlocks(e.blocks) ?? "";
4858
+ if (hasZeroUsage(e)) {
4859
+ rows.push({
4860
+ kind: "model",
4861
+ event: e,
4862
+ tOffsetMs: e.tOffsetMs,
4863
+ gapMs: e.gapMs
4864
+ });
4865
+ if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
4866
+ rows.push({
4867
+ kind: "error",
4868
+ event: e,
4869
+ message: txt,
4870
+ tOffsetMs: e.tOffsetMs,
4871
+ gapMs: 0
4872
+ });
4873
+ }
4874
+ continue;
4875
+ }
4876
+ if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
4877
+ rows.push({
4878
+ kind: "error",
4879
+ event: e,
4880
+ message: txt,
4881
+ tOffsetMs: e.tOffsetMs,
4882
+ gapMs: e.gapMs
4883
+ });
4884
+ continue;
4885
+ }
4886
+ const grouped = e.messageId ? byMessageId.get(e.messageId) ?? [e] : [e];
4887
+ rows.push({
4888
+ kind: "agent",
4889
+ event: e,
4890
+ groupedEvents: grouped,
4891
+ tOffsetMs: e.tOffsetMs,
4892
+ gapMs: e.gapMs
4893
+ });
4894
+ continue;
4895
+ }
4896
+ }
4897
+ return rows;
4898
+ }
4899
+ var INTERRUPT_RE, RATE_LIMIT_RE, SLASH_COMMAND_RE, TASK_NOTIFICATION_RE;
4900
+ var init_presentation = __esm({
4901
+ "../parser/dist/presentation.js"() {
4902
+ "use strict";
4903
+ init_user_input();
4904
+ INTERRUPT_RE = /\[request interrupted|interrupted by user/i;
4905
+ RATE_LIMIT_RE = /rate.?limit|overloaded_error|api error|Error sending message/i;
4906
+ SLASH_COMMAND_RE = /<command-name>(\/[^<\s]+)<\/command-name>(?:[\s\S]*?<command-args>([\s\S]*?)<\/command-args>)?/;
4907
+ TASK_NOTIFICATION_RE = /<task-notification>/;
4908
+ }
4909
+ });
4910
+
4911
+ // ../parser/dist/aggregate.js
4912
+ function isoDay(d) {
4913
+ return toLocalDay(d.getTime());
4914
+ }
4915
+ function rangeDays(start2, end) {
4916
+ const out = [];
4917
+ const cur = new Date(start2.getFullYear(), start2.getMonth(), start2.getDate());
4918
+ const stop2 = new Date(end.getFullYear(), end.getMonth(), end.getDate());
4919
+ while (cur.getTime() <= stop2.getTime()) {
4920
+ out.push(new Date(cur));
4921
+ cur.setDate(cur.getDate() + 1);
4922
+ }
4923
+ return out;
4924
+ }
4925
+ function calendarWeek(ref = /* @__PURE__ */ new Date()) {
4926
+ const d = new Date(ref.getFullYear(), ref.getMonth(), ref.getDate());
4927
+ const dow = d.getDay();
4928
+ const daysSinceMon = (dow + 6) % 7;
4929
+ const monday = new Date(d);
4930
+ monday.setDate(d.getDate() - daysSinceMon);
4931
+ const sunday = new Date(monday);
4932
+ sunday.setDate(monday.getDate() + 6);
4933
+ return { start: monday, end: sunday };
4934
+ }
4935
+ function priorCalendarWeek(ref = /* @__PURE__ */ new Date()) {
4936
+ const cur = calendarWeek(ref);
4937
+ const prevEnd = new Date(cur.start);
4938
+ prevEnd.setDate(cur.start.getDate() - 1);
4939
+ const prevStart = new Date(prevEnd);
4940
+ prevStart.setDate(prevEnd.getDate() - 6);
4941
+ return { start: prevStart, end: prevEnd };
4942
+ }
4943
+ function last4CompletedWeeks(ref = /* @__PURE__ */ new Date()) {
4944
+ const { end } = priorCalendarWeek(ref);
4945
+ const start2 = new Date(end);
4946
+ start2.setDate(end.getDate() - 27);
4947
+ return { start: start2, end };
4948
+ }
4949
+ function calendarMonth(ref = /* @__PURE__ */ new Date()) {
4950
+ const start2 = new Date(ref.getFullYear(), ref.getMonth(), 1);
4951
+ const end = new Date(ref.getFullYear(), ref.getMonth() + 1, 0);
4952
+ return { start: start2, end };
4953
+ }
4954
+ function priorCalendarMonth(ref = /* @__PURE__ */ new Date()) {
4955
+ const start2 = new Date(ref.getFullYear(), ref.getMonth() - 1, 1);
4956
+ const end = new Date(ref.getFullYear(), ref.getMonth(), 0);
4957
+ return { start: start2, end };
4958
+ }
4959
+ function aggregateConcurrency(bursts, period) {
4960
+ const days = rangeDays(period.start, period.end);
4961
+ const byDayKey = /* @__PURE__ */ new Map();
4962
+ for (const d of days)
4963
+ byDayKey.set(isoDay(d), { peak: 0, has_cross_project: false });
4964
+ for (const b of bursts) {
4965
+ const dayKey = isoDay(new Date(b.startMs));
4966
+ const cur = byDayKey.get(dayKey);
4967
+ if (!cur)
4968
+ continue;
4969
+ if (b.peak > cur.peak)
4970
+ cur.peak = b.peak;
4971
+ if (b.crossProject)
4972
+ cur.has_cross_project = true;
4973
+ }
4974
+ const by_day = days.map((d) => {
4975
+ const k = isoDay(d);
4976
+ const v = byDayKey.get(k);
4977
+ return { date: k, peak: v.peak, has_cross_project: v.has_cross_project };
4978
+ });
4979
+ let peak = 0;
4980
+ let peak_day;
4981
+ let multi_agent_days = 0;
4982
+ let cross_project_days = 0;
4983
+ for (const d of by_day) {
4984
+ if (d.peak > peak) {
4985
+ peak = d.peak;
4986
+ peak_day = d.date;
4987
+ }
4988
+ if (d.peak >= 3)
4989
+ multi_agent_days++;
4990
+ if (d.has_cross_project)
4991
+ cross_project_days++;
4992
+ }
4993
+ return { by_day, peak, peak_day, multi_agent_days, cross_project_days };
4994
+ }
4995
+ var init_aggregate = __esm({
4996
+ "../parser/dist/aggregate.js"() {
4997
+ "use strict";
4998
+ init_analytics();
4999
+ }
5000
+ });
5001
+
5002
+ // ../parser/dist/index.js
5003
+ var dist_exports = {};
5004
+ __export(dist_exports, {
5005
+ CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
5006
+ CODEX_METADATA: () => CODEX_METADATA,
5007
+ GEMINI_METADATA: () => GEMINI_METADATA,
5008
+ PRICES: () => PRICES,
5009
+ RATE_PER_PCT: () => RATE_PER_PCT,
5010
+ RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
5011
+ RATE_PER_PCT_7D: () => RATE_PER_PCT_7D,
5012
+ agentMetadata: () => agentMetadata,
5013
+ aggregateConcurrency: () => aggregateConcurrency,
5014
+ buildGanttDay: () => buildGanttDay,
5015
+ buildMegaRows: () => buildMegaRows,
5016
+ buildPresentation: () => buildPresentation,
5017
+ buildSpendIndex: () => buildSpendIndex,
5018
+ calendarMonth: () => calendarMonth,
5019
+ calendarWeek: () => calendarWeek,
5020
+ canonicalProjectName: () => canonicalProjectName,
5021
+ collectSnapPairRates: () => collectSnapPairRates,
5022
+ computeActiveSegments: () => computeActiveSegments,
5023
+ computeBurstsFromSessions: () => computeBurstsFromSessions,
5024
+ computeParallelism: () => computeParallelism,
5025
+ computeParallelismBursts: () => computeParallelismBursts,
5026
+ dailyActivity: () => dailyActivity,
5027
+ daysBetween: () => daysBetween,
5028
+ detectParallelRuns: () => detectParallelRuns,
5029
+ detectPrMarkers: () => detectPrMarkers,
5030
+ dollarsInRange: () => dollarsInRange,
5031
+ dollarsInWindow: () => dollarsInWindow,
5032
+ eventDollars: () => eventDollars,
5033
+ getAgentMetadata: () => getAgentMetadata,
5034
+ groupByProject: () => groupByProject,
5035
+ groupByTeam: () => groupByTeam,
5036
+ groupSnapsByCycle: () => groupSnapsByCycle,
5037
+ highLevelMetrics: () => highLevelMetrics,
5038
+ isAgentKind: () => isAgentKind,
5039
+ isFrameworkInjectedUserInput: () => isFrameworkInjectedUserInput,
5040
+ last4CompletedWeeks: () => last4CompletedWeeks,
5041
+ modelFamily: () => modelFamily,
5042
+ parseTranscript: () => parseTranscript,
5043
+ predictAnchored: () => predictAnchored,
5044
+ predictUtilization: () => predictUtilization,
5045
+ priorCalendarMonth: () => priorCalendarMonth,
5046
+ priorCalendarWeek: () => priorCalendarWeek,
5047
+ rowPrimaryIndex: () => rowPrimaryIndex,
5048
+ sessionAirTimeMs: () => sessionAirTimeMs,
5049
+ sessionDay: () => sessionDay,
5050
+ stripFrameworkBoilerplate: () => stripFrameworkBoilerplate,
5051
+ summarizeBursts: () => summarizeBursts,
5052
+ toLocalDay: () => toLocalDay,
5053
+ userSoloRate: () => userSoloRate,
5054
+ worktreeName: () => worktreeName
5055
+ });
5056
+ var init_dist = __esm({
5057
+ "../parser/dist/index.js"() {
5058
+ "use strict";
5059
+ init_types2();
5060
+ init_parser();
5061
+ init_user_input();
5062
+ init_presentation();
5063
+ init_analytics();
5064
+ init_aggregate();
5065
+ init_calibration();
5066
+ init_agent_metadata();
5067
+ init_team();
5068
+ }
5069
+ });
5070
+
5071
+ // ../entries/dist/signals.js
5072
+ function classifyUserInputSource(text) {
5073
+ if (!text)
5074
+ return "human";
5075
+ const stripped = stripFrameworkBoilerplate(text);
5076
+ if (!stripped)
5077
+ return "system_instruction";
5078
+ if (TEAMMATE_RE.test(stripped))
5079
+ return "teammate";
5080
+ if (SKILL_LOAD_RE.test(stripped))
5081
+ return "skill_load";
5082
+ if (SLASH_COMMAND_RE2.test(stripped))
5083
+ return "slash_command";
5084
+ return "human";
5085
+ }
5086
+ function classifySubagentRole(sa) {
5087
+ const text = `${sa.description} ${sa.prompt_preview}`.toLowerCase();
5088
+ if (/\b(re-?review|review[s]?|verify|audit|spec[- ]review|code[- ]quality|code[- ]reuse|efficiency review|sanity check|quick test)\b/.test(text)) {
5089
+ return "reviewer";
5090
+ }
5091
+ if (/\b(implement|build chunk|build task|initialize|create the|add the)\b/.test(text)) {
5092
+ return "implementer";
5093
+ }
5094
+ if (/\bexplore\b|\binventory\b|\bmap\b.*\b(codebase|repo|branch)\b|\baudit\b.*coverage/.test(text)) {
5095
+ return "explorer";
5096
+ }
5097
+ if (/\b(investigate|research|reverse[- ]engineer|study|analy[sz]e|look up|tell me|brief me on|find out)\b/.test(text)) {
5098
+ return "researcher";
5099
+ }
5100
+ if (/\b(env(?:ironment)? setup|configure|setup|bootstrap)\b/.test(text)) {
5101
+ return "env-setup";
5102
+ }
5103
+ if (/\b(polish|cleanup|fix|refactor)\b/.test(text)) {
5104
+ return "polish";
5105
+ }
5106
+ return "other";
5107
+ }
5108
+ function isStockSubagentType(type) {
5109
+ return STOCK_SUBAGENT_PREFIXES.test(type);
5110
+ }
5111
+ function inferWorkingShape(entry) {
5112
+ if (entry.numbers.turn_count < 2)
5113
+ return null;
5114
+ const subagents = entry.subagents ?? [];
5115
+ const roles = subagents.map(classifySubagentRole);
5116
+ const reviewerCount = roles.filter((r) => r === "reviewer").length;
5117
+ const implementerCount = roles.filter((r) => r === "implementer").length;
5118
+ const explorerOrResearcher = roles.filter((r) => r === "explorer" || r === "researcher").length;
5119
+ const hasBackground = subagents.some((sa) => sa.background);
5120
+ if (implementerCount >= 2) {
5121
+ const chunkRefs = subagents.filter((sa) => /\b(chunk|task)\s*\d+/i.test(`${sa.description} ${sa.prompt_preview}`));
5122
+ if (chunkRefs.length >= 2)
5123
+ return "chunk-implementation";
5124
+ }
5125
+ if (reviewerCount >= 3 && implementerCount === 0) {
5126
+ const lensSigs = /* @__PURE__ */ new Set();
5127
+ for (let i = 0; i < subagents.length; i++) {
5128
+ if (roles[i] !== "reviewer")
5129
+ continue;
5130
+ const sig = subagents[i].description.toLowerCase().replace(/[^a-z0-9 ]/g, "").split(/\s+/).filter((w) => w.length > 2).slice(0, 3).join("|");
5131
+ lensSigs.add(sig);
5132
+ }
5133
+ if (lensSigs.size >= 3)
5134
+ return "reviewer-triad";
5135
+ }
5136
+ if (reviewerCount >= 2)
5137
+ return "spec-review-loop";
5138
+ if (explorerOrResearcher >= 2 || explorerOrResearcher >= 1 && implementerCount >= 1) {
5139
+ return "research-then-build";
5140
+ }
5141
+ if (hasBackground && subagents.length >= 1)
5142
+ return "background-coordinated";
5143
+ if (subagents.length === 0) {
5144
+ const first = (entry.first_user || "").trim().toLowerCase();
5145
+ if (/^continue\b/.test(first) || first === "continue.")
5146
+ return "solo-continuation";
5147
+ const skills = Object.keys(entry.skills ?? {});
5148
+ if (skills.some((s) => /brainstorm|writing-plans|brainstorming/i.test(s)))
5149
+ return "solo-design";
5150
+ return "solo-build";
5151
+ }
5152
+ return "solo-build";
5153
+ }
5154
+ function detectPromptFrames(text) {
5155
+ if (!text)
5156
+ return [];
5157
+ const out = [];
5158
+ if (/<teammate-message\b/i.test(text))
5159
+ out.push("teammate");
5160
+ if (/<task-notification\b/i.test(text))
5161
+ out.push("task-notification");
5162
+ if (/<local-command-caveat\b/i.test(text))
5163
+ out.push("local-command-caveat");
5164
+ if (/<command-(message|name)\b/i.test(text))
5165
+ out.push("slash-command");
5166
+ if (/\[Image #\d+\]/.test(text))
5167
+ out.push("image-attached");
5168
+ if (/\b(here'?s the (handoff|handover) prompt|session-close summary|wrap-up summary|all wrapped up|all captured\.)\b/i.test(text) || /^##? (Wrap-up|Session conclusion|Handoff)\b/m.test(text) || /^# Handoff:/m.test(text)) {
5169
+ out.push("handoff-prose");
5170
+ }
5171
+ return out;
5172
+ }
5173
+ function classifySkill(name) {
5174
+ if (name.startsWith("(ToolSearch:"))
5175
+ return "infra";
5176
+ if (STOCK_SKILL_PREFIXES.test(name))
5177
+ return "stock";
5178
+ if (name === "using-superpowers")
5179
+ return "stock";
5180
+ return "user";
5181
+ }
5182
+ function detectExternalRef(text) {
5183
+ if (!text)
5184
+ return null;
5185
+ if (/<teammate-message|<task-notification|<local-command-caveat/i.test(text.slice(0, 400)))
5186
+ return null;
5187
+ for (const { kind, re } of EXTERNAL_REF_PATTERNS) {
5188
+ const m = text.match(re);
5189
+ if (m)
5190
+ return { kind, preview: text.slice(0, 160) };
5191
+ }
5192
+ return null;
5193
+ }
5194
+ function bucketVerbosity(n) {
5195
+ if (n < 100)
5196
+ return "short";
5197
+ if (n < 500)
5198
+ return "medium";
5199
+ if (n < 2e3)
5200
+ return "long";
5201
+ return "very_long";
5202
+ }
5203
+ function computeEntrySignals(entry) {
5204
+ const fu = entry.first_user || "";
5205
+ const verbosity = bucketVerbosity(fu.length);
4645
5206
  const ext = detectExternalRef(fu);
4646
5207
  const external_refs = ext ? [ext] : [];
4647
5208
  const skillNames = Object.keys(entry.skills ?? {});
@@ -4659,13 +5220,14 @@ function computeEntrySignals(entry) {
4659
5220
  continuation_kind
4660
5221
  };
4661
5222
  }
4662
- var TEAMMATE_RE, SKILL_LOAD_RE, SLASH_COMMAND_RE, STOCK_SUBAGENT_PREFIXES, STOCK_SKILL_PREFIXES, EXTERNAL_REF_PATTERNS;
5223
+ var TEAMMATE_RE, SKILL_LOAD_RE, SLASH_COMMAND_RE2, STOCK_SUBAGENT_PREFIXES, STOCK_SKILL_PREFIXES, EXTERNAL_REF_PATTERNS;
4663
5224
  var init_signals = __esm({
4664
5225
  "../entries/dist/signals.js"() {
4665
5226
  "use strict";
5227
+ init_dist();
4666
5228
  TEAMMATE_RE = /^<teammate-message\b/;
4667
5229
  SKILL_LOAD_RE = /^Base directory for this skill:/;
4668
- SLASH_COMMAND_RE = /^<command-name>|^<local-command-stdout>/;
5230
+ SLASH_COMMAND_RE2 = /^<command-name>|^<local-command-stdout>/;
4669
5231
  STOCK_SUBAGENT_PREFIXES = /^(general-purpose|Explore|Plan|claude-code-guide|playwright-qa-verifier|statusline-setup|frontend-design:|code-review:|code-simplifier:|codex:|superpowers:)/;
4670
5232
  STOCK_SKILL_PREFIXES = /^(superpowers|mcp__|frontend-design|code-review|codex|claude-code-guide|claude-api):/i;
4671
5233
  EXTERNAL_REF_PATTERNS = [
@@ -4705,7 +5267,7 @@ var init_flag_glossary = __esm({
4705
5267
  });
4706
5268
 
4707
5269
  // ../entries/dist/index.js
4708
- var init_dist = __esm({
5270
+ var init_dist2 = __esm({
4709
5271
  "../entries/dist/index.js"() {
4710
5272
  "use strict";
4711
5273
  init_types();
@@ -5756,7 +6318,7 @@ function custom(check, _params = {}, fatal) {
5756
6318
  return ZodAny.create();
5757
6319
  }
5758
6320
  var ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, BRAND, ZodBranded, ZodPipeline, ZodReadonly, late, ZodFirstPartyTypeKind, instanceOfType, stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType, ostring, onumber, oboolean, coerce, NEVER;
5759
- var init_types2 = __esm({
6321
+ var init_types3 = __esm({
5760
6322
  "../../node_modules/zod/v3/types.js"() {
5761
6323
  init_ZodError();
5762
6324
  init_errors();
@@ -9136,7 +9698,7 @@ var init_external = __esm({
9136
9698
  init_parseUtil();
9137
9699
  init_typeAliases();
9138
9700
  init_util();
9139
- init_types2();
9701
+ init_types3();
9140
9702
  init_ZodError();
9141
9703
  }
9142
9704
  });
@@ -9598,778 +10160,316 @@ function applyEnrichmentError(entry, errorMessage, model, costUsd, generatedAt,
9598
10160
  ...entry.enrichment,
9599
10161
  status: "pending",
9600
10162
  generated_at: generatedAt,
9601
- model,
9602
- cost_usd: costUsd,
9603
- error: errorMessage
9604
- // retry_count NOT incremented on rate-limit.
9605
- };
9606
- return { ...entry, enrichment: enrichment2 };
9607
- }
9608
- const enrichment = {
9609
- ...entry.enrichment,
9610
- status: "error",
9611
- generated_at: generatedAt,
9612
- model,
9613
- cost_usd: costUsd,
9614
- error: errorMessage,
9615
- retry_count: (entry.enrichment.retry_count ?? 0) + 1
9616
- };
9617
- return { ...entry, enrichment };
9618
- }
9619
- var DEFAULT_MODEL;
9620
- var init_enrich2 = __esm({
9621
- "../entries/dist/enrich.js"() {
9622
- "use strict";
9623
- init_signals();
9624
- init_enrich();
9625
- init_llm_runner();
9626
- DEFAULT_MODEL = "sonnet";
9627
- }
9628
- });
9629
-
9630
- // ../entries/dist/budget.js
9631
- import { appendFileSync as appendFileSync3, readFileSync as readFileSync8, existsSync as existsSync8, mkdirSync as mkdirSync6 } from "node:fs";
9632
- import { dirname as dirname7, join as join9 } from "node:path";
9633
- import { homedir as homedir8 } from "node:os";
9634
- function spendPath() {
9635
- if (spendPathCached)
9636
- return spendPathCached;
9637
- spendPathCached = join9(homedir8(), ".cclens", "llm-spend.jsonl");
9638
- return spendPathCached;
9639
- }
9640
- function __setSpendPathForTest(path5) {
9641
- spendPathCached = path5;
9642
- }
9643
- function appendSpend(record) {
9644
- const p = spendPath();
9645
- mkdirSync6(dirname7(p), { recursive: true });
9646
- appendFileSync3(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
9647
- }
9648
- function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
9649
- const p = spendPath();
9650
- if (!existsSync8(p))
9651
- return 0;
9652
- const year = now.getUTCFullYear();
9653
- const month2 = now.getUTCMonth();
9654
- let total = 0;
9655
- const raw = readFileSync8(p, "utf8");
9656
- for (const line of raw.split("\n")) {
9657
- if (!line)
9658
- continue;
9659
- let rec;
9660
- try {
9661
- rec = JSON.parse(line);
9662
- } catch {
9663
- continue;
9664
- }
9665
- const ts = new Date(rec.ts);
9666
- if (Number.isNaN(ts.getTime()))
9667
- continue;
9668
- if (ts.getUTCFullYear() !== year || ts.getUTCMonth() !== month2)
9669
- continue;
9670
- total += rec.cost_usd;
9671
- }
9672
- return total;
9673
- }
9674
- var spendPathCached;
9675
- var init_budget = __esm({
9676
- "../entries/dist/budget.js"() {
9677
- "use strict";
9678
- spendPathCached = null;
9679
- }
9680
- });
9681
-
9682
- // ../entries/dist/pipeline-lock.js
9683
- import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync2, existsSync as existsSync9, readFileSync as readFileSync9, statSync as statSync2 } from "node:fs";
9684
- import { join as join10 } from "node:path";
9685
- import { homedir as homedir9 } from "node:os";
9686
- function lockPath() {
9687
- if (lockPathCached)
9688
- return lockPathCached;
9689
- lockPathCached = join10(homedir9(), ".cclens", "llm-interactive.lock");
9690
- return lockPathCached;
9691
- }
9692
- function __setInteractiveLockPathForTest(path5) {
9693
- lockPathCached = path5;
9694
- }
9695
- function touchLock() {
9696
- writeFileSync5(lockPath(), String(process.pid), "utf8");
9697
- }
9698
- function writeInteractiveLock() {
9699
- touchLock();
9700
- if (heartbeat)
9701
- clearInterval(heartbeat);
9702
- heartbeat = setInterval(() => {
9703
- try {
9704
- touchLock();
9705
- } catch {
9706
- }
9707
- }, HEARTBEAT_MS);
9708
- heartbeat.unref?.();
9709
- }
9710
- function removeInteractiveLock() {
9711
- if (heartbeat) {
9712
- clearInterval(heartbeat);
9713
- heartbeat = null;
9714
- }
9715
- try {
9716
- unlinkSync2(lockPath());
9717
- } catch {
9718
- }
9719
- }
9720
- function pidAlive(pid) {
9721
- try {
9722
- process.kill(pid, 0);
9723
- return true;
9724
- } catch {
9725
- return false;
9726
- }
9727
- }
9728
- function interactiveLockFresh(nowMs) {
9729
- const p = lockPath();
9730
- if (!existsSync9(p))
9731
- return false;
9732
- try {
9733
- const mtime = statSync2(p).mtimeMs;
9734
- if (nowMs - mtime > STALE_MS)
9735
- return false;
9736
- const pid = Number(readFileSync9(p, "utf8").trim());
9737
- if (!Number.isFinite(pid) || pid <= 0)
9738
- return false;
9739
- if (!pidAlive(pid))
9740
- return false;
9741
- return true;
9742
- } catch {
9743
- return false;
9744
- }
9745
- }
9746
- var STALE_MS, HEARTBEAT_MS, lockPathCached, heartbeat;
9747
- var init_pipeline_lock = __esm({
9748
- "../entries/dist/pipeline-lock.js"() {
9749
- "use strict";
9750
- STALE_MS = 60 * 1e3;
9751
- HEARTBEAT_MS = 30 * 1e3;
9752
- lockPathCached = null;
9753
- heartbeat = null;
9754
- }
9755
- });
9756
-
9757
- // ../entries/dist/queue.js
9758
- function toLocalDay2(ms) {
9759
- const d = new Date(ms);
9760
- const y = d.getFullYear();
9761
- const m = String(d.getMonth() + 1).padStart(2, "0");
9762
- const day2 = String(d.getDate()).padStart(2, "0");
9763
- return `${y}-${m}-${day2}`;
9764
- }
9765
- async function runEnrichmentQueue(settings, opts = {}) {
9766
- if (!settings.enabled)
9767
- return { skipped: "disabled" };
9768
- const now = opts.now ?? (() => Date.now());
9769
- if (interactiveLockFresh(now()))
9770
- return { skipped: "interactive_in_progress" };
9771
- const budget = settings.monthlyBudgetUsd ?? Infinity;
9772
- if (monthToDateSpend() >= budget)
9773
- return { skipped: "budget_cap_reached" };
9774
- const queue = listEntriesWithStatus(["pending", "error"]).filter((e) => (e.enrichment.retry_count ?? 0) < MAX_RETRY_COUNT);
9775
- const todayLocal = toLocalDay2(now());
9776
- let enriched = 0, errors = 0, skipped = 0;
9777
- for (const entry of queue) {
9778
- if (entry.local_day === todayLocal) {
9779
- skipped++;
9780
- continue;
9781
- }
9782
- const endMs = Date.parse(entry.end_iso);
9783
- if (!Number.isNaN(endMs) && now() - endMs < THIRTY_MIN_MS) {
9784
- skipped++;
9785
- continue;
9786
- }
9787
- if (monthToDateSpend() >= budget)
9788
- break;
9789
- try {
9790
- const { entry: result, usage: usage2 } = await enrichEntry(entry, {
9791
- model: settings.model,
9792
- callLLM: opts.callLLM
9793
- });
9794
- writeEntry(result);
9795
- if (result.enrichment.status === "done") {
9796
- enriched++;
9797
- appendSpend({
9798
- ts: (/* @__PURE__ */ new Date()).toISOString(),
9799
- caller: "daemon",
9800
- model: result.enrichment.model ?? settings.model,
9801
- input_tokens: usage2?.input_tokens ?? 0,
9802
- output_tokens: usage2?.output_tokens ?? 0,
9803
- cost_usd: result.enrichment.cost_usd ?? 0,
9804
- kind: "entry_enrich",
9805
- ref: `${result.session_id}__${result.local_day}`
9806
- });
9807
- } else {
9808
- errors++;
9809
- }
9810
- } catch (err) {
9811
- errors++;
9812
- const failed = {
9813
- ...entry,
9814
- enrichment: {
9815
- ...entry.enrichment,
9816
- status: "error",
9817
- retry_count: (entry.enrichment.retry_count ?? 0) + 1,
9818
- error: err.message,
9819
- generated_at: (/* @__PURE__ */ new Date()).toISOString()
9820
- }
9821
- };
9822
- writeEntry(failed);
9823
- }
10163
+ model,
10164
+ cost_usd: costUsd,
10165
+ error: errorMessage
10166
+ // retry_count NOT incremented on rate-limit.
10167
+ };
10168
+ return { ...entry, enrichment: enrichment2 };
9824
10169
  }
9825
- return { enriched, errors, skipped };
10170
+ const enrichment = {
10171
+ ...entry.enrichment,
10172
+ status: "error",
10173
+ generated_at: generatedAt,
10174
+ model,
10175
+ cost_usd: costUsd,
10176
+ error: errorMessage,
10177
+ retry_count: (entry.enrichment.retry_count ?? 0) + 1
10178
+ };
10179
+ return { ...entry, enrichment };
9826
10180
  }
9827
- var THIRTY_MIN_MS, MAX_RETRY_COUNT;
9828
- var init_queue = __esm({
9829
- "../entries/dist/queue.js"() {
10181
+ var DEFAULT_MODEL;
10182
+ var init_enrich2 = __esm({
10183
+ "../entries/dist/enrich.js"() {
9830
10184
  "use strict";
9831
- init_fs2();
9832
- init_enrich2();
9833
- init_budget();
9834
- init_pipeline_lock();
9835
- THIRTY_MIN_MS = 30 * 60 * 1e3;
9836
- MAX_RETRY_COUNT = 3;
10185
+ init_signals();
10186
+ init_enrich();
10187
+ init_llm_runner();
10188
+ DEFAULT_MODEL = "sonnet";
9837
10189
  }
9838
10190
  });
9839
10191
 
9840
- // ../entries/dist/settings.js
9841
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, renameSync as renameSync3, chmodSync as chmodSync2, mkdirSync as mkdirSync7, existsSync as existsSync10 } from "node:fs";
9842
- import { dirname as dirname8, join as join11 } from "node:path";
9843
- import { homedir as homedir10 } from "node:os";
9844
- function settingsPath() {
9845
- if (settingsPathCached)
9846
- return settingsPathCached;
9847
- settingsPathCached = join11(homedir10(), ".cclens", "settings.json");
9848
- return settingsPathCached;
10192
+ // ../entries/dist/budget.js
10193
+ import { appendFileSync as appendFileSync3, readFileSync as readFileSync8, existsSync as existsSync8, mkdirSync as mkdirSync6 } from "node:fs";
10194
+ import { dirname as dirname7, join as join9 } from "node:path";
10195
+ import { homedir as homedir8 } from "node:os";
10196
+ function spendPath() {
10197
+ if (spendPathCached)
10198
+ return spendPathCached;
10199
+ spendPathCached = join9(homedir8(), ".cclens", "llm-spend.jsonl");
10200
+ return spendPathCached;
9849
10201
  }
9850
- function __setSettingsPathForTest(path5) {
9851
- settingsPathCached = path5;
10202
+ function __setSpendPathForTest(path5) {
10203
+ spendPathCached = path5;
9852
10204
  }
9853
- function toDisk(s) {
9854
- return {
9855
- ai_features: {
9856
- enabled: s.ai_features.enabled,
9857
- model: s.ai_features.model,
9858
- monthly_budget_usd: s.ai_features.monthlyBudgetUsd,
9859
- auto_backfill_last_week: s.ai_features.autoBackfillLastWeek,
9860
- auto_backfill_yesterday: s.ai_features.autoBackfillYesterday
9861
- }
9862
- };
10205
+ function appendSpend(record) {
10206
+ const p = spendPath();
10207
+ mkdirSync6(dirname7(p), { recursive: true });
10208
+ appendFileSync3(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
9863
10209
  }
9864
- function fromDisk(d) {
9865
- const af = d.ai_features ?? {};
9866
- return {
9867
- ai_features: {
9868
- enabled: af.enabled ?? DEFAULT_SETTINGS.ai_features.enabled,
9869
- model: af.model ?? DEFAULT_SETTINGS.ai_features.model,
9870
- monthlyBudgetUsd: af.monthly_budget_usd ?? null,
9871
- autoBackfillLastWeek: af.auto_backfill_last_week ?? DEFAULT_SETTINGS.ai_features.autoBackfillLastWeek,
9872
- autoBackfillYesterday: af.auto_backfill_yesterday ?? DEFAULT_SETTINGS.ai_features.autoBackfillYesterday
10210
+ function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
10211
+ const p = spendPath();
10212
+ if (!existsSync8(p))
10213
+ return 0;
10214
+ const year = now.getUTCFullYear();
10215
+ const month2 = now.getUTCMonth();
10216
+ let total = 0;
10217
+ const raw = readFileSync8(p, "utf8");
10218
+ for (const line of raw.split("\n")) {
10219
+ if (!line)
10220
+ continue;
10221
+ let rec;
10222
+ try {
10223
+ rec = JSON.parse(line);
10224
+ } catch {
10225
+ continue;
9873
10226
  }
9874
- };
9875
- }
9876
- function readSettings() {
9877
- const p = settingsPath();
9878
- if (!existsSync10(p))
9879
- return DEFAULT_SETTINGS;
9880
- try {
9881
- const raw = readFileSync10(p, "utf8");
9882
- return fromDisk(JSON.parse(raw));
9883
- } catch {
9884
- return DEFAULT_SETTINGS;
9885
- }
9886
- }
9887
- function writeSettings(s) {
9888
- const p = settingsPath();
9889
- mkdirSync7(dirname8(p), { recursive: true });
9890
- const tmp = `${p}.tmp`;
9891
- writeFileSync6(tmp, JSON.stringify(toDisk(s), null, 2), { encoding: "utf8" });
9892
- if (process.platform !== "win32") {
9893
- chmodSync2(tmp, 384);
10227
+ const ts = new Date(rec.ts);
10228
+ if (Number.isNaN(ts.getTime()))
10229
+ continue;
10230
+ if (ts.getUTCFullYear() !== year || ts.getUTCMonth() !== month2)
10231
+ continue;
10232
+ total += rec.cost_usd;
9894
10233
  }
9895
- renameSync3(tmp, p);
10234
+ return total;
9896
10235
  }
9897
- var DEFAULT_SETTINGS, settingsPathCached;
9898
- var init_settings = __esm({
9899
- "../entries/dist/settings.js"() {
9900
- "use strict";
9901
- DEFAULT_SETTINGS = {
9902
- ai_features: {
9903
- enabled: true,
9904
- model: "sonnet",
9905
- monthlyBudgetUsd: null,
9906
- autoBackfillLastWeek: true,
9907
- autoBackfillYesterday: true
9908
- }
9909
- };
9910
- settingsPathCached = null;
9911
- }
9912
- });
9913
-
9914
- // ../parser/dist/types.js
9915
- var init_types3 = __esm({
9916
- "../parser/dist/types.js"() {
10236
+ var spendPathCached;
10237
+ var init_budget = __esm({
10238
+ "../entries/dist/budget.js"() {
9917
10239
  "use strict";
10240
+ spendPathCached = null;
9918
10241
  }
9919
10242
  });
9920
10243
 
9921
- // ../parser/dist/presentation.js
9922
- function rowPrimaryIndex(r) {
9923
- if (r.kind === "tool-group")
9924
- return r.events[0].index;
9925
- return r.event.index;
10244
+ // ../entries/dist/pipeline-lock.js
10245
+ import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync2, existsSync as existsSync9, readFileSync as readFileSync9, statSync as statSync2 } from "node:fs";
10246
+ import { join as join10 } from "node:path";
10247
+ import { homedir as homedir9 } from "node:os";
10248
+ function lockPath() {
10249
+ if (lockPathCached)
10250
+ return lockPathCached;
10251
+ lockPathCached = join10(homedir9(), ".cclens", "llm-interactive.lock");
10252
+ return lockPathCached;
9926
10253
  }
9927
- function buildMegaRows(rows) {
9928
- const out = [];
9929
- let buffer = [];
9930
- const flush = () => {
9931
- if (buffer.length === 0)
9932
- return;
9933
- let agentMessages = 0;
9934
- let toolCalls = 0;
9935
- let errors = 0;
9936
- let firstAgentIndex;
9937
- const toolMap = /* @__PURE__ */ new Map();
9938
- const seenMsgIds = /* @__PURE__ */ new Set();
9939
- const tokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
9940
- for (let i = 0; i < buffer.length; i++) {
9941
- const r = buffer[i];
9942
- if (r.kind === "agent") {
9943
- agentMessages++;
9944
- if (firstAgentIndex === void 0)
9945
- firstAgentIndex = i;
9946
- const msgId = r.event.messageId;
9947
- const usage2 = r.event.usage;
9948
- if (msgId && !seenMsgIds.has(msgId) && usage2) {
9949
- seenMsgIds.add(msgId);
9950
- tokens.input += usage2.input;
9951
- tokens.output += usage2.output;
9952
- tokens.cacheRead += usage2.cacheRead;
9953
- tokens.cacheWrite += usage2.cacheWrite;
9954
- }
9955
- } else if (r.kind === "tool-group") {
9956
- toolCalls += r.count;
9957
- for (const t of r.toolNames) {
9958
- toolMap.set(t.name, (toolMap.get(t.name) ?? 0) + t.count);
9959
- }
9960
- } else if (r.kind === "error") {
9961
- errors++;
9962
- }
9963
- }
9964
- let finalAgentIndex;
9965
- for (let i = buffer.length - 1; i >= 0; i--) {
9966
- const r = buffer[i];
9967
- if (r.kind !== "agent")
9968
- continue;
9969
- const prev = buffer[i - 1];
9970
- if (prev?.kind === "task-notification")
9971
- continue;
9972
- finalAgentIndex = i;
9973
- break;
9974
- }
9975
- if (finalAgentIndex === void 0) {
9976
- for (let i = buffer.length - 1; i >= 0; i--) {
9977
- if (buffer[i].kind === "agent") {
9978
- finalAgentIndex = i;
9979
- break;
9980
- }
9981
- }
9982
- }
9983
- const firstAgentPreview = firstAgentIndex !== void 0 && buffer[firstAgentIndex].kind === "agent" ? buffer[firstAgentIndex].event.preview : void 0;
9984
- const finalAgentPreview = finalAgentIndex !== void 0 && buffer[finalAgentIndex].kind === "agent" ? buffer[finalAgentIndex].event.preview : void 0;
9985
- const toolNames = Array.from(toolMap.entries()).sort((a, b) => b[1] - a[1]).map(([name, count]) => ({ name, count }));
9986
- const first = buffer[0];
9987
- const last = buffer[buffer.length - 1];
9988
- const start2 = first.tOffsetMs;
9989
- const end = last.tOffsetMs;
9990
- const durationMs = start2 !== void 0 && end !== void 0 ? end - start2 : void 0;
9991
- out.push({
9992
- kind: "turn",
9993
- rows: buffer,
9994
- firstPrimaryIndex: rowPrimaryIndex(first),
9995
- tOffsetMs: start2,
9996
- durationMs,
9997
- summary: {
9998
- agentMessages,
9999
- toolCalls,
10000
- errors,
10001
- firstAgentPreview,
10002
- finalAgentPreview,
10003
- firstAgentIndex,
10004
- finalAgentIndex,
10005
- toolNames,
10006
- totalTokens: tokens
10007
- }
10008
- });
10009
- buffer = [];
10010
- };
10011
- for (const r of rows) {
10012
- if (r.kind === "user" || r.kind === "interrupt") {
10013
- flush();
10014
- out.push(r);
10015
- } else {
10016
- buffer.push(r);
10017
- }
10018
- }
10019
- flush();
10020
- return out;
10254
+ function __setInteractiveLockPathForTest(path5) {
10255
+ lockPathCached = path5;
10021
10256
  }
10022
- function parseTaskNotification(text) {
10023
- if (!TASK_NOTIFICATION_RE.test(text))
10024
- return null;
10025
- const pick = (tag) => {
10026
- const m = text.match(new RegExp(`<${tag}>([\\s\\S]*?)<\\/${tag}>`));
10027
- return m ? m[1].trim() : void 0;
10028
- };
10029
- const statusRaw = (pick("status") ?? "").toLowerCase();
10030
- let status2 = "unknown";
10031
- if (statusRaw === "success" || statusRaw === "ok" || statusRaw === "done" || statusRaw === "completed")
10032
- status2 = "success";
10033
- else if (statusRaw === "failed" || statusRaw === "error" || statusRaw === "fail")
10034
- status2 = "failed";
10035
- else if (statusRaw === "running" || statusRaw === "in_progress")
10036
- status2 = "running";
10037
- return {
10038
- status: status2,
10039
- summary: pick("summary") ?? "Background task notification",
10040
- taskId: pick("task-id"),
10041
- toolUseId: pick("tool-use-id"),
10042
- outputFile: pick("output-file")
10043
- };
10257
+ function touchLock() {
10258
+ writeFileSync5(lockPath(), String(process.pid), "utf8");
10044
10259
  }
10045
- function isAttachmentOrMeta(e) {
10046
- return e.role === "system" || e.role === "meta";
10260
+ function writeInteractiveLock() {
10261
+ touchLock();
10262
+ if (heartbeat)
10263
+ clearInterval(heartbeat);
10264
+ heartbeat = setInterval(() => {
10265
+ try {
10266
+ touchLock();
10267
+ } catch {
10268
+ }
10269
+ }, HEARTBEAT_MS);
10270
+ heartbeat.unref?.();
10047
10271
  }
10048
- function firstTextOfBlocks(blocks) {
10049
- for (const b of blocks) {
10050
- if (b?.type === "text")
10051
- return b.text;
10272
+ function removeInteractiveLock() {
10273
+ if (heartbeat) {
10274
+ clearInterval(heartbeat);
10275
+ heartbeat = null;
10276
+ }
10277
+ try {
10278
+ unlinkSync2(lockPath());
10279
+ } catch {
10052
10280
  }
10053
- return void 0;
10054
10281
  }
10055
- function hasZeroUsage(e) {
10056
- if (!e.usage)
10282
+ function pidAlive(pid) {
10283
+ try {
10284
+ process.kill(pid, 0);
10285
+ return true;
10286
+ } catch {
10057
10287
  return false;
10058
- const u = e.usage;
10059
- return u.input === 0 && u.output === 0 && u.cacheRead === 0 && u.cacheWrite === 0;
10060
- }
10061
- function buildPresentation(events) {
10062
- const byMessageId = /* @__PURE__ */ new Map();
10063
- for (const e of events) {
10064
- if (!e.messageId)
10065
- continue;
10066
- const list = byMessageId.get(e.messageId) ?? [];
10067
- list.push(e);
10068
- byMessageId.set(e.messageId, list);
10069
10288
  }
10070
- const visible = events.filter((e) => {
10071
- if (isAttachmentOrMeta(e))
10289
+ }
10290
+ function interactiveLockFresh(nowMs) {
10291
+ const p = lockPath();
10292
+ if (!existsSync9(p))
10293
+ return false;
10294
+ try {
10295
+ const mtime = statSync2(p).mtimeMs;
10296
+ if (nowMs - mtime > STALE_MS)
10072
10297
  return false;
10073
- if (e.role === "tool-result")
10298
+ const pid = Number(readFileSync9(p, "utf8").trim());
10299
+ if (!Number.isFinite(pid) || pid <= 0)
10074
10300
  return false;
10075
- if (e.role === "agent-thinking")
10301
+ if (!pidAlive(pid))
10076
10302
  return false;
10077
- if (e.role === "user") {
10078
- const txt = firstTextOfBlocks(e.blocks) ?? "";
10079
- if (SKILL_CONTENT_RE.test(txt))
10080
- return false;
10081
- }
10082
10303
  return true;
10083
- });
10084
- const rows = [];
10085
- for (let i = 0; i < visible.length; i++) {
10086
- const e = visible[i];
10087
- if (e.role === "tool-call") {
10088
- const start2 = i;
10089
- while (i + 1 < visible.length && visible[i + 1].role === "tool-call") {
10090
- i++;
10091
- }
10092
- const group = visible.slice(start2, i + 1);
10093
- const order = [];
10094
- const counts = /* @__PURE__ */ new Map();
10095
- for (const ev of group) {
10096
- const name = ev.toolName ?? "tool";
10097
- if (!counts.has(name))
10098
- order.push(name);
10099
- counts.set(name, (counts.get(name) ?? 0) + 1);
10100
- }
10101
- const toolNames = order.map((name) => ({
10102
- name,
10103
- count: counts.get(name) ?? 1
10104
- }));
10105
- rows.push({
10106
- kind: "tool-group",
10107
- toolNames,
10108
- count: group.length,
10109
- events: group,
10110
- tOffsetMs: group[0].tOffsetMs,
10111
- gapMs: group[0].gapMs
10112
- });
10304
+ } catch {
10305
+ return false;
10306
+ }
10307
+ }
10308
+ var STALE_MS, HEARTBEAT_MS, lockPathCached, heartbeat;
10309
+ var init_pipeline_lock = __esm({
10310
+ "../entries/dist/pipeline-lock.js"() {
10311
+ "use strict";
10312
+ STALE_MS = 60 * 1e3;
10313
+ HEARTBEAT_MS = 30 * 1e3;
10314
+ lockPathCached = null;
10315
+ heartbeat = null;
10316
+ }
10317
+ });
10318
+
10319
+ // ../entries/dist/queue.js
10320
+ function toLocalDay2(ms) {
10321
+ const d = new Date(ms);
10322
+ const y = d.getFullYear();
10323
+ const m = String(d.getMonth() + 1).padStart(2, "0");
10324
+ const day2 = String(d.getDate()).padStart(2, "0");
10325
+ return `${y}-${m}-${day2}`;
10326
+ }
10327
+ async function runEnrichmentQueue(settings, opts = {}) {
10328
+ if (!settings.enabled)
10329
+ return { skipped: "disabled" };
10330
+ const now = opts.now ?? (() => Date.now());
10331
+ if (interactiveLockFresh(now()))
10332
+ return { skipped: "interactive_in_progress" };
10333
+ const budget = settings.monthlyBudgetUsd ?? Infinity;
10334
+ if (monthToDateSpend() >= budget)
10335
+ return { skipped: "budget_cap_reached" };
10336
+ const queue = listEntriesWithStatus(["pending", "error"]).filter((e) => (e.enrichment.retry_count ?? 0) < MAX_RETRY_COUNT);
10337
+ const todayLocal = toLocalDay2(now());
10338
+ let enriched = 0, errors = 0, skipped = 0;
10339
+ for (const entry of queue) {
10340
+ if (entry.local_day === todayLocal) {
10341
+ skipped++;
10113
10342
  continue;
10114
10343
  }
10115
- if (e.role === "user") {
10116
- const txt = firstTextOfBlocks(e.blocks) ?? "";
10117
- const taskNotif = parseTaskNotification(txt);
10118
- if (taskNotif) {
10119
- rows.push({
10120
- kind: "task-notification",
10121
- event: e,
10122
- status: taskNotif.status,
10123
- summary: taskNotif.summary,
10124
- taskId: taskNotif.taskId,
10125
- toolUseId: taskNotif.toolUseId,
10126
- outputFile: taskNotif.outputFile,
10127
- tOffsetMs: e.tOffsetMs,
10128
- gapMs: e.gapMs
10129
- });
10130
- continue;
10131
- }
10132
- if (INTERRUPT_RE.test(txt)) {
10133
- rows.push({
10134
- kind: "interrupt",
10135
- event: e,
10136
- tOffsetMs: e.tOffsetMs,
10137
- gapMs: e.gapMs
10138
- });
10139
- continue;
10140
- }
10141
- const slashMatch = txt.match(SLASH_COMMAND_RE2);
10142
- if (slashMatch) {
10143
- const cmd = slashMatch[1];
10144
- const args2 = (slashMatch[2] ?? "").trim();
10145
- const pretty = args2 ? `${cmd} ${args2}` : cmd;
10146
- rows.push({
10147
- kind: "user",
10148
- event: e,
10149
- displayPreview: pretty,
10150
- displayBlocks: [{ type: "text", text: pretty }],
10151
- tOffsetMs: e.tOffsetMs,
10152
- gapMs: e.gapMs
10153
- });
10154
- continue;
10155
- }
10156
- rows.push({
10157
- kind: "user",
10158
- event: e,
10159
- tOffsetMs: e.tOffsetMs,
10160
- gapMs: e.gapMs
10161
- });
10344
+ const endMs = Date.parse(entry.end_iso);
10345
+ if (!Number.isNaN(endMs) && now() - endMs < THIRTY_MIN_MS) {
10346
+ skipped++;
10162
10347
  continue;
10163
10348
  }
10164
- if (e.role === "agent") {
10165
- const txt = firstTextOfBlocks(e.blocks) ?? "";
10166
- if (hasZeroUsage(e)) {
10167
- rows.push({
10168
- kind: "model",
10169
- event: e,
10170
- tOffsetMs: e.tOffsetMs,
10171
- gapMs: e.gapMs
10172
- });
10173
- if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
10174
- rows.push({
10175
- kind: "error",
10176
- event: e,
10177
- message: txt,
10178
- tOffsetMs: e.tOffsetMs,
10179
- gapMs: 0
10180
- });
10181
- }
10182
- continue;
10183
- }
10184
- if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
10185
- rows.push({
10186
- kind: "error",
10187
- event: e,
10188
- message: txt,
10189
- tOffsetMs: e.tOffsetMs,
10190
- gapMs: e.gapMs
10191
- });
10192
- continue;
10193
- }
10194
- const grouped = e.messageId ? byMessageId.get(e.messageId) ?? [e] : [e];
10195
- rows.push({
10196
- kind: "agent",
10197
- event: e,
10198
- groupedEvents: grouped,
10199
- tOffsetMs: e.tOffsetMs,
10200
- gapMs: e.gapMs
10349
+ if (monthToDateSpend() >= budget)
10350
+ break;
10351
+ try {
10352
+ const { entry: result, usage: usage2 } = await enrichEntry(entry, {
10353
+ model: settings.model,
10354
+ callLLM: opts.callLLM
10201
10355
  });
10202
- continue;
10356
+ writeEntry(result);
10357
+ if (result.enrichment.status === "done") {
10358
+ enriched++;
10359
+ appendSpend({
10360
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
10361
+ caller: "daemon",
10362
+ model: result.enrichment.model ?? settings.model,
10363
+ input_tokens: usage2?.input_tokens ?? 0,
10364
+ output_tokens: usage2?.output_tokens ?? 0,
10365
+ cost_usd: result.enrichment.cost_usd ?? 0,
10366
+ kind: "entry_enrich",
10367
+ ref: `${result.session_id}__${result.local_day}`
10368
+ });
10369
+ } else {
10370
+ errors++;
10371
+ }
10372
+ } catch (err) {
10373
+ errors++;
10374
+ const failed = {
10375
+ ...entry,
10376
+ enrichment: {
10377
+ ...entry.enrichment,
10378
+ status: "error",
10379
+ retry_count: (entry.enrichment.retry_count ?? 0) + 1,
10380
+ error: err.message,
10381
+ generated_at: (/* @__PURE__ */ new Date()).toISOString()
10382
+ }
10383
+ };
10384
+ writeEntry(failed);
10203
10385
  }
10204
10386
  }
10205
- return rows;
10387
+ return { enriched, errors, skipped };
10206
10388
  }
10207
- var INTERRUPT_RE, RATE_LIMIT_RE, SKILL_CONTENT_RE, SLASH_COMMAND_RE2, TASK_NOTIFICATION_RE;
10208
- var init_presentation = __esm({
10209
- "../parser/dist/presentation.js"() {
10389
+ var THIRTY_MIN_MS, MAX_RETRY_COUNT;
10390
+ var init_queue = __esm({
10391
+ "../entries/dist/queue.js"() {
10210
10392
  "use strict";
10211
- INTERRUPT_RE = /\[request interrupted|interrupted by user/i;
10212
- RATE_LIMIT_RE = /rate.?limit|overloaded_error|api error|Error sending message/i;
10213
- SKILL_CONTENT_RE = /^Base directory for this skill:/;
10214
- SLASH_COMMAND_RE2 = /<command-name>(\/[^<\s]+)<\/command-name>(?:[\s\S]*?<command-args>([\s\S]*?)<\/command-args>)?/;
10215
- TASK_NOTIFICATION_RE = /<task-notification>/;
10393
+ init_fs2();
10394
+ init_enrich2();
10395
+ init_budget();
10396
+ init_pipeline_lock();
10397
+ THIRTY_MIN_MS = 30 * 60 * 1e3;
10398
+ MAX_RETRY_COUNT = 3;
10216
10399
  }
10217
10400
  });
10218
10401
 
10219
- // ../parser/dist/aggregate.js
10220
- function isoDay(d) {
10221
- return toLocalDay(d.getTime());
10222
- }
10223
- function rangeDays(start2, end) {
10224
- const out = [];
10225
- const cur = new Date(start2.getFullYear(), start2.getMonth(), start2.getDate());
10226
- const stop2 = new Date(end.getFullYear(), end.getMonth(), end.getDate());
10227
- while (cur.getTime() <= stop2.getTime()) {
10228
- out.push(new Date(cur));
10229
- cur.setDate(cur.getDate() + 1);
10230
- }
10231
- return out;
10232
- }
10233
- function calendarWeek(ref = /* @__PURE__ */ new Date()) {
10234
- const d = new Date(ref.getFullYear(), ref.getMonth(), ref.getDate());
10235
- const dow = d.getDay();
10236
- const daysSinceMon = (dow + 6) % 7;
10237
- const monday = new Date(d);
10238
- monday.setDate(d.getDate() - daysSinceMon);
10239
- const sunday = new Date(monday);
10240
- sunday.setDate(monday.getDate() + 6);
10241
- return { start: monday, end: sunday };
10242
- }
10243
- function priorCalendarWeek(ref = /* @__PURE__ */ new Date()) {
10244
- const cur = calendarWeek(ref);
10245
- const prevEnd = new Date(cur.start);
10246
- prevEnd.setDate(cur.start.getDate() - 1);
10247
- const prevStart = new Date(prevEnd);
10248
- prevStart.setDate(prevEnd.getDate() - 6);
10249
- return { start: prevStart, end: prevEnd };
10250
- }
10251
- function last4CompletedWeeks(ref = /* @__PURE__ */ new Date()) {
10252
- const { end } = priorCalendarWeek(ref);
10253
- const start2 = new Date(end);
10254
- start2.setDate(end.getDate() - 27);
10255
- return { start: start2, end };
10402
+ // ../entries/dist/settings.js
10403
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, renameSync as renameSync3, chmodSync as chmodSync2, mkdirSync as mkdirSync7, existsSync as existsSync10 } from "node:fs";
10404
+ import { dirname as dirname8, join as join11 } from "node:path";
10405
+ import { homedir as homedir10 } from "node:os";
10406
+ function settingsPath() {
10407
+ if (settingsPathCached)
10408
+ return settingsPathCached;
10409
+ settingsPathCached = join11(homedir10(), ".cclens", "settings.json");
10410
+ return settingsPathCached;
10256
10411
  }
10257
- function calendarMonth(ref = /* @__PURE__ */ new Date()) {
10258
- const start2 = new Date(ref.getFullYear(), ref.getMonth(), 1);
10259
- const end = new Date(ref.getFullYear(), ref.getMonth() + 1, 0);
10260
- return { start: start2, end };
10412
+ function __setSettingsPathForTest(path5) {
10413
+ settingsPathCached = path5;
10261
10414
  }
10262
- function priorCalendarMonth(ref = /* @__PURE__ */ new Date()) {
10263
- const start2 = new Date(ref.getFullYear(), ref.getMonth() - 1, 1);
10264
- const end = new Date(ref.getFullYear(), ref.getMonth(), 0);
10265
- return { start: start2, end };
10415
+ function toDisk(s) {
10416
+ return {
10417
+ ai_features: {
10418
+ enabled: s.ai_features.enabled,
10419
+ model: s.ai_features.model,
10420
+ monthly_budget_usd: s.ai_features.monthlyBudgetUsd,
10421
+ auto_backfill_last_week: s.ai_features.autoBackfillLastWeek,
10422
+ auto_backfill_yesterday: s.ai_features.autoBackfillYesterday
10423
+ }
10424
+ };
10266
10425
  }
10267
- function aggregateConcurrency(bursts, period) {
10268
- const days = rangeDays(period.start, period.end);
10269
- const byDayKey = /* @__PURE__ */ new Map();
10270
- for (const d of days)
10271
- byDayKey.set(isoDay(d), { peak: 0, has_cross_project: false });
10272
- for (const b of bursts) {
10273
- const dayKey = isoDay(new Date(b.startMs));
10274
- const cur = byDayKey.get(dayKey);
10275
- if (!cur)
10276
- continue;
10277
- if (b.peak > cur.peak)
10278
- cur.peak = b.peak;
10279
- if (b.crossProject)
10280
- cur.has_cross_project = true;
10281
- }
10282
- const by_day = days.map((d) => {
10283
- const k = isoDay(d);
10284
- const v = byDayKey.get(k);
10285
- return { date: k, peak: v.peak, has_cross_project: v.has_cross_project };
10286
- });
10287
- let peak = 0;
10288
- let peak_day;
10289
- let multi_agent_days = 0;
10290
- let cross_project_days = 0;
10291
- for (const d of by_day) {
10292
- if (d.peak > peak) {
10293
- peak = d.peak;
10294
- peak_day = d.date;
10426
+ function fromDisk(d) {
10427
+ const af = d.ai_features ?? {};
10428
+ return {
10429
+ ai_features: {
10430
+ enabled: af.enabled ?? DEFAULT_SETTINGS.ai_features.enabled,
10431
+ model: af.model ?? DEFAULT_SETTINGS.ai_features.model,
10432
+ monthlyBudgetUsd: af.monthly_budget_usd ?? null,
10433
+ autoBackfillLastWeek: af.auto_backfill_last_week ?? DEFAULT_SETTINGS.ai_features.autoBackfillLastWeek,
10434
+ autoBackfillYesterday: af.auto_backfill_yesterday ?? DEFAULT_SETTINGS.ai_features.autoBackfillYesterday
10295
10435
  }
10296
- if (d.peak >= 3)
10297
- multi_agent_days++;
10298
- if (d.has_cross_project)
10299
- cross_project_days++;
10436
+ };
10437
+ }
10438
+ function readSettings() {
10439
+ const p = settingsPath();
10440
+ if (!existsSync10(p))
10441
+ return DEFAULT_SETTINGS;
10442
+ try {
10443
+ const raw = readFileSync10(p, "utf8");
10444
+ return fromDisk(JSON.parse(raw));
10445
+ } catch {
10446
+ return DEFAULT_SETTINGS;
10300
10447
  }
10301
- return { by_day, peak, peak_day, multi_agent_days, cross_project_days };
10302
10448
  }
10303
- var init_aggregate = __esm({
10304
- "../parser/dist/aggregate.js"() {
10305
- "use strict";
10306
- init_analytics();
10449
+ function writeSettings(s) {
10450
+ const p = settingsPath();
10451
+ mkdirSync7(dirname8(p), { recursive: true });
10452
+ const tmp = `${p}.tmp`;
10453
+ writeFileSync6(tmp, JSON.stringify(toDisk(s), null, 2), { encoding: "utf8" });
10454
+ if (process.platform !== "win32") {
10455
+ chmodSync2(tmp, 384);
10307
10456
  }
10308
- });
10309
-
10310
- // ../parser/dist/index.js
10311
- var dist_exports = {};
10312
- __export(dist_exports, {
10313
- CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
10314
- CODEX_METADATA: () => CODEX_METADATA,
10315
- GEMINI_METADATA: () => GEMINI_METADATA,
10316
- PRICES: () => PRICES,
10317
- RATE_PER_PCT: () => RATE_PER_PCT,
10318
- RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
10319
- RATE_PER_PCT_7D: () => RATE_PER_PCT_7D,
10320
- agentMetadata: () => agentMetadata,
10321
- aggregateConcurrency: () => aggregateConcurrency,
10322
- buildGanttDay: () => buildGanttDay,
10323
- buildMegaRows: () => buildMegaRows,
10324
- buildPresentation: () => buildPresentation,
10325
- buildSpendIndex: () => buildSpendIndex,
10326
- calendarMonth: () => calendarMonth,
10327
- calendarWeek: () => calendarWeek,
10328
- canonicalProjectName: () => canonicalProjectName,
10329
- collectSnapPairRates: () => collectSnapPairRates,
10330
- computeActiveSegments: () => computeActiveSegments,
10331
- computeBurstsFromSessions: () => computeBurstsFromSessions,
10332
- computeParallelism: () => computeParallelism,
10333
- computeParallelismBursts: () => computeParallelismBursts,
10334
- dailyActivity: () => dailyActivity,
10335
- daysBetween: () => daysBetween,
10336
- detectParallelRuns: () => detectParallelRuns,
10337
- detectPrMarkers: () => detectPrMarkers,
10338
- dollarsInRange: () => dollarsInRange,
10339
- dollarsInWindow: () => dollarsInWindow,
10340
- eventDollars: () => eventDollars,
10341
- getAgentMetadata: () => getAgentMetadata,
10342
- groupByProject: () => groupByProject,
10343
- groupByTeam: () => groupByTeam,
10344
- groupSnapsByCycle: () => groupSnapsByCycle,
10345
- highLevelMetrics: () => highLevelMetrics,
10346
- isAgentKind: () => isAgentKind,
10347
- last4CompletedWeeks: () => last4CompletedWeeks,
10348
- modelFamily: () => modelFamily,
10349
- parseTranscript: () => parseTranscript,
10350
- predictAnchored: () => predictAnchored,
10351
- predictUtilization: () => predictUtilization,
10352
- priorCalendarMonth: () => priorCalendarMonth,
10353
- priorCalendarWeek: () => priorCalendarWeek,
10354
- rowPrimaryIndex: () => rowPrimaryIndex,
10355
- sessionAirTimeMs: () => sessionAirTimeMs,
10356
- sessionDay: () => sessionDay,
10357
- summarizeBursts: () => summarizeBursts,
10358
- toLocalDay: () => toLocalDay,
10359
- userSoloRate: () => userSoloRate,
10360
- worktreeName: () => worktreeName
10361
- });
10362
- var init_dist2 = __esm({
10363
- "../parser/dist/index.js"() {
10457
+ renameSync3(tmp, p);
10458
+ }
10459
+ var DEFAULT_SETTINGS, settingsPathCached;
10460
+ var init_settings = __esm({
10461
+ "../entries/dist/settings.js"() {
10364
10462
  "use strict";
10365
- init_types3();
10366
- init_parser();
10367
- init_presentation();
10368
- init_analytics();
10369
- init_aggregate();
10370
- init_calibration();
10371
- init_agent_metadata();
10372
- init_team();
10463
+ DEFAULT_SETTINGS = {
10464
+ ai_features: {
10465
+ enabled: true,
10466
+ model: "sonnet",
10467
+ monthlyBudgetUsd: null,
10468
+ autoBackfillLastWeek: true,
10469
+ autoBackfillYesterday: true
10470
+ }
10471
+ };
10472
+ settingsPathCached = null;
10373
10473
  }
10374
10474
  });
10375
10475
 
@@ -10436,7 +10536,7 @@ var init_digest_day = __esm({
10436
10536
  "../entries/dist/prompts/digest-day.js"() {
10437
10537
  "use strict";
10438
10538
  init_zod();
10439
- init_dist2();
10539
+ init_dist();
10440
10540
  AGENT_NAMING_TABLE = agentMetadata.map((m) => ` - agent="${m.kind}" \u2192 render as "${m.displayName}"`).join("\n");
10441
10541
  SuggestionSchema = external_exports.object({
10442
10542
  headline: external_exports.string().min(1).max(80),
@@ -11027,7 +11127,7 @@ var init_digest_day_pipeline = __esm({
11027
11127
  init_budget();
11028
11128
  init_pipeline_lock();
11029
11129
  init_fs();
11030
- init_dist2();
11130
+ init_dist();
11031
11131
  THIRTY_MIN_MS2 = 30 * 60 * 1e3;
11032
11132
  MAX_RETRY_COUNT2 = 3;
11033
11133
  }
@@ -11223,7 +11323,7 @@ var init_digest_week = __esm({
11223
11323
  "../entries/dist/prompts/digest-week.js"() {
11224
11324
  "use strict";
11225
11325
  init_zod();
11226
- init_dist2();
11326
+ init_dist();
11227
11327
  AGENT_NAMING_TABLE2 = agentMetadata.map((m) => ` - agent="${m.kind}" \u2192 render as "${m.displayName}"`).join("\n");
11228
11328
  DateRegex = /^\d{4}-\d{2}-\d{2}$/;
11229
11329
  ProjectAreaResponseSchema = external_exports.object({
@@ -13740,7 +13840,7 @@ Exit codes:
13740
13840
  var init_entries = __esm({
13741
13841
  "src/commands/entries.ts"() {
13742
13842
  "use strict";
13743
- init_dist();
13843
+ init_dist2();
13744
13844
  init_fs2();
13745
13845
  init_args();
13746
13846
  }
@@ -14241,11 +14341,12 @@ async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG4, configOverr
14241
14341
  return { paired: false, sentSnapshots: 0, insertedSnapshots: 0, skippedSnapshots: 0, batches: 0 };
14242
14342
  }
14243
14343
  const raw = readSnapshots(filePath);
14244
- if (raw.length === 0) {
14344
+ const claudeOnly = raw.filter((s) => !s.agent || s.agent === "claude-code");
14345
+ if (claudeOnly.length === 0) {
14245
14346
  log("info", "team backfill: no usage snapshots to send");
14246
14347
  return { paired: true, sentSnapshots: 0, insertedSnapshots: 0, skippedSnapshots: 0, batches: 0 };
14247
14348
  }
14248
- const wire = raw.map(rawToWire);
14349
+ const wire = claudeOnly.map(rawToWire);
14249
14350
  const batches = chunk(wire, BATCH_SIZE);
14250
14351
  const planTier = await getPlanTier(PROFILE_CACHE).catch(() => null) ?? void 0;
14251
14352
  let inserted = 0;
@@ -14309,7 +14410,7 @@ var init_backfill = __esm({
14309
14410
  // src/team/push.ts
14310
14411
  import { randomUUID as randomUUID2 } from "node:crypto";
14311
14412
  function readLatestUsageSnapshotForWire(filePath, nowMs = Date.now()) {
14312
- const raw = latestSnapshot(filePath);
14413
+ const raw = latestClaudeCodeSnapshot(filePath);
14313
14414
  if (!raw) return null;
14314
14415
  const capturedMs = Date.parse(raw.captured_at);
14315
14416
  if (Number.isNaN(capturedMs)) return null;
@@ -14379,7 +14480,7 @@ var SNAPSHOT_FRESHNESS_MS;
14379
14480
  var init_push = __esm({
14380
14481
  "src/team/push.ts"() {
14381
14482
  "use strict";
14382
- init_dist2();
14483
+ init_dist();
14383
14484
  init_storage();
14384
14485
  SNAPSHOT_FRESHNESS_MS = 10 * 60 * 1e3;
14385
14486
  }
@@ -14454,7 +14555,7 @@ async function runTeamSync(log = noopLog2, configOverride) {
14454
14555
  if (!config) return { paired: false, pushed: 0, queued: 0, queuedDrained: 0 };
14455
14556
  try {
14456
14557
  const { listSessions: listSessions2, loadCalibrationCurve: loadCalibrationCurve2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
14457
- const { toLocalDay: toLocalDay4 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
14558
+ const { toLocalDay: toLocalDay4 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
14458
14559
  const today = toLocalDay4(Date.now());
14459
14560
  const sessions = await listSessions2({ limit: 1e4 });
14460
14561
  const rollups = buildRollupsForRange(sessions, config.lastSyncedDay);
@@ -15268,7 +15369,7 @@ async function main() {
15268
15369
  case "version":
15269
15370
  case "--version":
15270
15371
  case "-v":
15271
- console.log(`fleetlens ${"0.9.0"}`);
15372
+ console.log(`fleetlens ${"0.10.0"}`);
15272
15373
  break;
15273
15374
  case "help":
15274
15375
  case "--help":