fleetlens 0.11.2 → 0.12.1

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 (214) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +3 -0
  3. package/app/apps/web/.next/build-manifest.json +3 -3
  4. package/app/apps/web/.next/prerender-manifest.json +3 -3
  5. package/app/apps/web/.next/routes-manifest.json +22 -0
  6. package/app/apps/web/.next/server/app/_global-error.html +1 -1
  7. package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
  8. package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/app/apps/web/.next/server/app/_not-found/page.js +2 -1
  14. package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/app/apps/web/.next/server/app/api/ask/route.js +1 -1
  17. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +2 -2
  19. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +2 -2
  21. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/digest/month-index/route.js +1 -1
  23. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  24. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +2 -2
  25. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  26. package/app/apps/web/.next/server/app/api/digest/week-index/route.js +1 -1
  27. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  28. package/app/apps/web/.next/server/app/api/events/route.js +1 -1
  29. package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/jobs/route.js +1 -1
  31. package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/api/pdf/[key]/route/app-paths-manifest.json +3 -0
  33. package/app/apps/web/.next/server/app/api/pdf/[key]/route/build-manifest.json +9 -0
  34. package/app/apps/web/.next/server/app/api/pdf/[key]/route/server-reference-manifest.json +4 -0
  35. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js +10 -0
  36. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.map +5 -0
  37. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -0
  38. package/app/apps/web/.next/server/app/api/pdf/[key]/route_client-reference-manifest.js +3 -0
  39. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js +1 -1
  40. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  41. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js +1 -1
  42. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/api/runs/route.js +1 -1
  44. package/app/apps/web/.next/server/app/api/runs/route.js.nft.json +1 -1
  45. package/app/apps/web/.next/server/app/api/settings/route.js +1 -1
  46. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  47. package/app/apps/web/.next/server/app/api/team-config/route.js +1 -1
  48. package/app/apps/web/.next/server/app/api/team-config/route.js.nft.json +1 -1
  49. package/app/apps/web/.next/server/app/api/workflow-agent/route/app-paths-manifest.json +3 -0
  50. package/app/apps/web/.next/server/app/api/workflow-agent/route/build-manifest.json +9 -0
  51. package/app/apps/web/.next/server/app/api/workflow-agent/route/server-reference-manifest.json +4 -0
  52. package/app/apps/web/.next/server/app/api/workflow-agent/route.js +7 -0
  53. package/app/apps/web/.next/server/app/api/workflow-agent/route.js.map +5 -0
  54. package/app/apps/web/.next/server/app/api/workflow-agent/route.js.nft.json +1 -0
  55. package/app/apps/web/.next/server/app/api/workflow-agent/route_client-reference-manifest.js +3 -0
  56. package/app/apps/web/.next/server/app/changelog/page.js +2 -1
  57. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  58. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  59. package/app/apps/web/.next/server/app/day/[date]/page.js +2 -1
  60. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  61. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  62. package/app/apps/web/.next/server/app/day/page.js +2 -1
  63. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  64. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  65. package/app/apps/web/.next/server/app/digest/[date]/page.js +2 -1
  66. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  67. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  68. package/app/apps/web/.next/server/app/digest/page.js +2 -1
  69. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  70. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  71. package/app/apps/web/.next/server/app/insights/[key]/page.js +2 -1
  72. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  73. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  74. package/app/apps/web/.next/server/app/insights/page.js +2 -1
  75. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  76. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  77. package/app/apps/web/.next/server/app/page.js +2 -1
  78. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  79. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  80. package/app/apps/web/.next/server/app/parallelism/page.js +2 -1
  81. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  82. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  83. package/app/apps/web/.next/server/app/print/[key]/page/app-paths-manifest.json +3 -0
  84. package/app/apps/web/.next/server/app/print/[key]/page/build-manifest.json +17 -0
  85. package/app/apps/web/.next/server/app/print/[key]/page/next-font-manifest.json +6 -0
  86. package/app/apps/web/.next/server/app/print/[key]/page/react-loadable-manifest.json +1 -0
  87. package/app/apps/web/.next/server/app/print/[key]/page/server-reference-manifest.json +4 -0
  88. package/app/apps/web/.next/server/app/print/[key]/page.js +19 -0
  89. package/app/apps/web/.next/server/app/print/[key]/page.js.map +5 -0
  90. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -0
  91. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +3 -0
  92. package/app/apps/web/.next/server/app/projects/[slug]/page.js +2 -1
  93. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  94. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  95. package/app/apps/web/.next/server/app/projects/page.js +2 -1
  96. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  97. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  98. package/app/apps/web/.next/server/app/runs/page.js +2 -1
  99. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  100. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  101. package/app/apps/web/.next/server/app/sessions/[id]/page.js +2 -1
  102. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  103. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  104. package/app/apps/web/.next/server/app/sessions/page.js +2 -1
  105. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  106. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  107. package/app/apps/web/.next/server/app/settings/page.js +2 -1
  108. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  109. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  110. package/app/apps/web/.next/server/app/team/page.js +2 -1
  111. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  112. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  113. package/app/apps/web/.next/server/app/usage/page.js +2 -1
  114. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  115. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  116. package/app/apps/web/.next/server/app-paths-manifest.json +3 -0
  117. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0455vu3._.js +2 -2
  118. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0_8zh-i._.js → [root-of-the-server]__04j3tng._.js} +2 -2
  119. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0jprdks._.js → [root-of-the-server]__0cnh3k4._.js} +2 -2
  120. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e.f-t.._.js +3 -0
  121. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0kc9e1n._.js +3 -0
  122. package/app/apps/web/.next/server/chunks/[root-of-the-server]__0y5p73y._.js +3 -0
  123. package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0ej_p3s._.js → [root-of-the-server]__132eosx._.js} +2 -2
  124. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_pdf_[key]_route_actions_0intcw9.js +3 -0
  125. package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_workflow-agent_route_actions_0gxw9tv.js +3 -0
  126. package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +1 -1
  127. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +3 -0
  128. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +3 -0
  129. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04eq6z2._.js +1 -1
  130. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04il6m2._.js +11 -0
  131. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0exckd4._.js +1 -1
  132. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0n-ax-5._.js +3 -0
  133. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0o03ymy._.js +2 -2
  134. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +1 -1
  135. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0z7mg0b._.js +1 -1
  136. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~.f_3z._.js +12 -0
  137. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__136-0me._.js +8 -0
  138. package/app/apps/web/.next/server/chunks/ssr/_0cgg5zi._.js +3 -0
  139. package/app/apps/web/.next/server/chunks/ssr/_0jw2sm7._.js +1 -1
  140. package/app/apps/web/.next/server/chunks/ssr/_0kajk31._.js +3 -0
  141. package/app/apps/web/.next/server/chunks/ssr/_0w.cv64._.js +8 -0
  142. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  143. package/app/apps/web/.next/server/chunks/ssr/apps_web_0.mu7c7._.js +1 -1
  144. package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_print_[key]_page_actions_0_ygul-.js +3 -0
  145. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_01d-iwx._.js +6 -0
  146. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_week-digest_tsx_0c9ha31._.js +3 -0
  147. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0k0tl52._.js +3 -0
  148. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +3 -0
  149. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +3 -0
  150. package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07orc4m.js +4 -0
  151. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_12.endt._.js +1 -1
  152. package/app/apps/web/.next/server/edge/chunks/[root-of-the-server]__0.sx~id._.js +11 -0
  153. package/app/apps/web/.next/server/edge/chunks/node_modules_next_dist_esm_build_templates_edge-wrapper_0p1t1z8.js +3 -0
  154. package/app/apps/web/.next/server/edge/chunks/turbopack-node_modules_next_dist_esm_build_templates_edge-wrapper_0mw-sqe.js +3 -0
  155. package/app/apps/web/.next/server/functions-config-manifest.json +4 -1
  156. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  157. package/app/apps/web/.next/server/middleware-manifest.json +30 -2
  158. package/app/apps/web/.next/server/pages/500.html +1 -1
  159. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  160. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  161. package/app/apps/web/.next/static/chunks/00xkqnvk4-d1-.js +10 -0
  162. package/app/apps/web/.next/static/chunks/03_7wmpodz36t.js +1 -0
  163. package/app/apps/web/.next/static/chunks/0716x58e1_2c5.js +1 -0
  164. package/app/apps/web/.next/static/chunks/0nnjldasalwdu.js +4 -0
  165. package/app/apps/web/.next/static/chunks/0okg13phslr1..js +4 -0
  166. package/app/apps/web/.next/static/chunks/0vf-3rauafbek.js +6 -0
  167. package/app/apps/web/.next/static/chunks/0vl27-vjob2_9.js +6 -0
  168. package/app/apps/web/.next/static/chunks/0yo458-7577lr.js +1 -0
  169. package/app/apps/web/.next/static/chunks/14bjditmmrn7l.js +1 -0
  170. package/app/apps/web/.next/static/rrY-ephAArv8tjJOXD622/_clientMiddlewareManifest.js +6 -0
  171. package/app/apps/web/app/api/events/route.ts +50 -2
  172. package/app/apps/web/app/api/pdf/[key]/route.ts +199 -0
  173. package/app/apps/web/app/api/workflow-agent/route.ts +27 -0
  174. package/app/apps/web/app/insights/[key]/page.tsx +4 -1
  175. package/app/apps/web/app/layout.tsx +23 -1
  176. package/app/apps/web/app/page.tsx +24 -1
  177. package/app/apps/web/app/print/[key]/page.tsx +91 -0
  178. package/app/apps/web/app/projects/[slug]/page.tsx +6 -7
  179. package/app/apps/web/app/projects/page.tsx +2 -3
  180. package/app/apps/web/app/sessions/[id]/session-view.tsx +1297 -19
  181. package/app/apps/web/app/sessions/sessions-grid.tsx +10 -1
  182. package/app/apps/web/components/dashboard-view.tsx +2 -1
  183. package/app/apps/web/components/export-pdf-button.tsx +76 -0
  184. package/app/apps/web/components/month-digest-view.tsx +10 -0
  185. package/app/apps/web/components/week-digest-view.tsx +10 -0
  186. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  187. package/app/apps/web/lib/entries-index.ts +5 -4
  188. package/app/apps/web/lib/find-chrome.ts +71 -0
  189. package/app/apps/web/middleware.ts +22 -0
  190. package/app/apps/web/package.json +1 -1
  191. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  192. package/dist/daemon-worker.js +1716 -281
  193. package/dist/index.js +1617 -195
  194. package/package.json +1 -1
  195. package/app/apps/web/.next/server/chunks/packages_parser_dist_04rh1zd._.js +0 -3
  196. package/app/apps/web/.next/server/chunks/packages_parser_dist_0ndsxe6._.js +0 -3
  197. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0_xpuh7._.js +0 -3
  198. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0d~2~le._.js +0 -8
  199. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +0 -12
  200. package/app/apps/web/.next/server/chunks/ssr/_02s1n-x._.js +0 -8
  201. package/app/apps/web/.next/server/chunks/ssr/_0fjbf--._.js +0 -3
  202. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +0 -6
  203. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0af94gl._.js +0 -3
  204. package/app/apps/web/.next/static/chunks/0.3mqbj24kwtc.js +0 -6
  205. package/app/apps/web/.next/static/chunks/0byz8fqw.exef.js +0 -1
  206. package/app/apps/web/.next/static/chunks/0l3ck.awv~4t7.js +0 -1
  207. package/app/apps/web/.next/static/chunks/0lxuac2v0_gdl.js +0 -6
  208. package/app/apps/web/.next/static/chunks/0m62vx92~0_0d.js +0 -1
  209. package/app/apps/web/.next/static/chunks/0rtba0saz74e1.js +0 -10
  210. package/app/apps/web/.next/static/chunks/0s4eyofh28l~u.js +0 -1
  211. package/app/apps/web/.next/static/chunks/0uev~g~qvbjv9.js +0 -4
  212. package/app/apps/web/.next/static/m6ibRSdAu8jD10VBA2OFH/_clientMiddlewareManifest.js +0 -1
  213. /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → rrY-ephAArv8tjJOXD622}/_buildManifest.js +0 -0
  214. /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → rrY-ephAArv8tjJOXD622}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -92,6 +92,16 @@ function findConductorWorkspace(projectName) {
92
92
  const canonicalEndIdx = m.index + m[0].length - workspaceName.length - 1 - trailingSlash;
93
93
  return { canonicalEndIdx, workspaceName };
94
94
  }
95
+ function findSupersetWorkspace(projectName) {
96
+ const idx = projectName.indexOf(SUPERSET_MARKER);
97
+ if (idx < 0)
98
+ return null;
99
+ const segs = projectName.slice(idx + SUPERSET_MARKER.length).split("/").filter(Boolean);
100
+ if (segs.length === 0)
101
+ return null;
102
+ const workspaceName = UUID_SEG_RE.test(segs[0]) ? segs[1] ?? segs[0] : segs[0];
103
+ return { canonical: projectName.slice(0, idx) + SUPERSET_MARKER + workspaceName, workspaceName };
104
+ }
95
105
  function canonicalProjectName(projectName) {
96
106
  const normalized = projectName.replace(/\/{2,}/g, "/");
97
107
  const wt = findWorktreeMarker(normalized);
@@ -100,6 +110,9 @@ function canonicalProjectName(projectName) {
100
110
  const cd = findConductorWorkspace(normalized);
101
111
  if (cd)
102
112
  return normalized.slice(0, cd.canonicalEndIdx);
113
+ const ss = findSupersetWorkspace(normalized);
114
+ if (ss)
115
+ return ss.canonical;
103
116
  return normalized;
104
117
  }
105
118
  function worktreeName(projectName) {
@@ -113,8 +126,16 @@ function worktreeName(projectName) {
113
126
  const cd = findConductorWorkspace(normalized);
114
127
  if (cd)
115
128
  return cd.workspaceName;
129
+ const ss = findSupersetWorkspace(normalized);
130
+ if (ss)
131
+ return ss.workspaceName;
116
132
  return null;
117
133
  }
134
+ function projectRepoName(projectName) {
135
+ const canonical = canonicalProjectName(projectName);
136
+ const segs = canonical.replace(/\/+$/, "").split("/").filter(Boolean);
137
+ return segs[segs.length - 1] || canonical;
138
+ }
118
139
  function makeDay(date) {
119
140
  return {
120
141
  date,
@@ -155,7 +176,19 @@ function dailyActivity(sessions) {
155
176
  };
156
177
  for (const s of sessions) {
157
178
  const startDay = sessionDay(s);
158
- if (startDay) {
179
+ if (s.dailyBreakdown && s.dailyBreakdown.length > 0) {
180
+ for (const d of s.dailyBreakdown) {
181
+ const bucket = touchBucket(d.day);
182
+ bucket.toolCalls += d.toolCalls;
183
+ bucket.turns += d.turns;
184
+ bucket.tokens.input += d.tokens.input;
185
+ bucket.tokens.output += d.tokens.output;
186
+ bucket.tokens.cacheRead += d.tokens.cacheRead;
187
+ bucket.tokens.cacheWrite += d.tokens.cacheWrite;
188
+ }
189
+ if (startDay)
190
+ touchBucket(startDay).durationMs += s.durationMs ?? 0;
191
+ } else if (startDay) {
159
192
  const bucket = touchBucket(startDay);
160
193
  bucket.toolCalls += s.toolCallCount ?? 0;
161
194
  bucket.turns += s.turnCount ?? 0;
@@ -165,31 +198,30 @@ function dailyActivity(sessions) {
165
198
  bucket.tokens.cacheWrite += s.totalUsage.cacheWrite;
166
199
  bucket.durationMs += s.durationMs ?? 0;
167
200
  }
201
+ const presenceDays = /* @__PURE__ */ new Set();
168
202
  const segments = s.activeSegments;
169
203
  if (segments && segments.length > 0) {
170
- const touchedDays = /* @__PURE__ */ new Set();
171
204
  for (const seg of segments) {
172
205
  let cur = seg.startMs;
173
206
  while (cur < seg.endMs) {
174
207
  const day2 = toLocalDay(cur);
175
- touchedDays.add(day2);
208
+ presenceDays.add(day2);
176
209
  const d = new Date(cur);
177
210
  d.setHours(24, 0, 0, 0);
178
211
  const dayEndMs = Math.min(d.getTime(), seg.endMs);
179
- const bucket = touchBucket(day2);
180
- bucket.airTimeMs += dayEndMs - cur;
212
+ touchBucket(day2).airTimeMs += dayEndMs - cur;
181
213
  cur = dayEndMs;
182
214
  }
183
215
  }
184
- for (const day2 of touchedDays) {
185
- const bucket = touchBucket(day2);
186
- bucket.sessions++;
187
- }
188
216
  } else if (startDay) {
189
- const bucket = touchBucket(startDay);
190
- bucket.sessions++;
191
- bucket.airTimeMs += s.airTimeMs ?? 0;
217
+ presenceDays.add(startDay);
218
+ touchBucket(startDay).airTimeMs += s.airTimeMs ?? 0;
192
219
  }
220
+ if (s.dailyBreakdown)
221
+ for (const d of s.dailyBreakdown)
222
+ presenceDays.add(d.day);
223
+ for (const day2 of presenceDays)
224
+ touchBucket(day2).sessions++;
193
225
  }
194
226
  const range = minDay && maxDay ? daysBetween(minDay, maxDay) : [];
195
227
  const out = [];
@@ -534,13 +566,13 @@ function summarizeBursts(bursts) {
534
566
  function groupByProject(sessions) {
535
567
  const map = /* @__PURE__ */ new Map();
536
568
  for (const s of sessions) {
537
- const canonical = canonicalProjectName(s.projectName);
538
- const key = canonical;
569
+ const repo = projectRepoName(s.projectName);
570
+ const key = repo;
539
571
  let cur = map.get(key);
540
572
  if (!cur) {
541
573
  cur = {
542
- projectDir: canonical,
543
- projectName: canonical,
574
+ projectDir: repo,
575
+ projectName: repo,
544
576
  sessions: [],
545
577
  rawProjectDirs: [],
546
578
  worktreeCount: 0,
@@ -582,7 +614,7 @@ function groupByProject(sessions) {
582
614
  }
583
615
  return Array.from(map.values()).sort((a, b) => (b.lastActiveMs ?? 0) - (a.lastActiveMs ?? 0));
584
616
  }
585
- var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
617
+ var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, SUPERSET_MARKER, UUID_SEG_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
586
618
  var init_analytics = __esm({
587
619
  "../parser/dist/analytics.js"() {
588
620
  "use strict";
@@ -593,6 +625,8 @@ var init_analytics = __esm({
593
625
  "/claude/worktrees/"
594
626
  ];
595
627
  CONDUCTOR_RE = /\/conductor\/workspaces\/[^/]+\/([^/]+)(?:\/|$)/;
628
+ SUPERSET_MARKER = "/.superset/worktrees/";
629
+ UUID_SEG_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
596
630
  PR_CREATE_RE = /gh\s+pr\s+create\b/i;
597
631
  PR_NUMBER_RE = /#(\d+)/;
598
632
  TITLE_FLAG_RE = /--title\s+["']([^"']+)["']/;
@@ -606,7 +640,7 @@ function getAgentMetadata(kind) {
606
640
  function isAgentKind(s) {
607
641
  return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
608
642
  }
609
- var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
643
+ var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
610
644
  var init_agent_metadata = __esm({
611
645
  "../parser/dist/agent-metadata.js"() {
612
646
  "use strict";
@@ -631,10 +665,26 @@ var init_agent_metadata = __esm({
631
665
  accentColor: "rgb(124, 92, 246)",
632
666
  iconChar: "\u273A"
633
667
  };
668
+ ANTIGRAVITY_METADATA = {
669
+ kind: "antigravity",
670
+ displayName: "Antigravity",
671
+ shortLabel: "Agy",
672
+ accentColor: "rgb(236, 72, 153)",
673
+ iconChar: "\u23C3"
674
+ };
675
+ COWORK_METADATA = {
676
+ kind: "cowork",
677
+ displayName: "Cowork",
678
+ shortLabel: "Cowork",
679
+ accentColor: "rgb(217, 119, 87)",
680
+ iconChar: "\u2318"
681
+ };
634
682
  agentMetadata = [
635
683
  CLAUDE_CODE_METADATA,
636
684
  CODEX_METADATA,
637
- GEMINI_METADATA
685
+ GEMINI_METADATA,
686
+ ANTIGRAVITY_METADATA,
687
+ COWORK_METADATA
638
688
  ];
639
689
  KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
640
690
  }
@@ -1216,9 +1266,31 @@ function parseTranscript(rawLines) {
1216
1266
  let linesAdded = 0;
1217
1267
  let linesRemoved = 0;
1218
1268
  const filesEdited = /* @__PURE__ */ new Set();
1269
+ const perDay = /* @__PURE__ */ new Map();
1270
+ const fallbackDay = startMs !== void 0 ? toLocalDay(startMs) : void 0;
1271
+ const dayBucket = (ts) => {
1272
+ let day2;
1273
+ if (ts) {
1274
+ const ms = Date.parse(ts);
1275
+ if (!Number.isNaN(ms))
1276
+ day2 = toLocalDay(ms);
1277
+ }
1278
+ day2 = day2 ?? fallbackDay;
1279
+ if (!day2)
1280
+ return void 0;
1281
+ let b = perDay.get(day2);
1282
+ if (!b) {
1283
+ b = { toolCalls: 0, turns: 0, tokens: { ...BLANK_USAGE2 } };
1284
+ perDay.set(day2, b);
1285
+ }
1286
+ return b;
1287
+ };
1219
1288
  for (const e of events) {
1220
1289
  if (e.role === "tool-call") {
1221
1290
  toolCallCount++;
1291
+ const tcDay = dayBucket(e.timestamp);
1292
+ if (tcDay)
1293
+ tcDay.toolCalls++;
1222
1294
  const toolBlock = e.blocks.find((b) => b && b.type === "tool_use");
1223
1295
  if (toolBlock) {
1224
1296
  const input = toolBlock.input ?? {};
@@ -1255,6 +1327,9 @@ function parseTranscript(rawLines) {
1255
1327
  firstUserPreview = e.teammateMessage ? e.teammateMessage.body : e.preview;
1256
1328
  }
1257
1329
  turnCount++;
1330
+ const turnDay = dayBucket(e.timestamp);
1331
+ if (turnDay)
1332
+ turnDay.turns++;
1258
1333
  lastUserPreview = e.preview;
1259
1334
  }
1260
1335
  }
@@ -1296,6 +1371,14 @@ function parseTranscript(rawLines) {
1296
1371
  totalUsage.output += u.output;
1297
1372
  totalUsage.cacheRead += u.cacheRead;
1298
1373
  totalUsage.cacheWrite += u.cacheWrite;
1374
+ const ts = typeof o.timestamp === "string" ? o.timestamp : void 0;
1375
+ const b = dayBucket(ts);
1376
+ if (b) {
1377
+ b.tokens.input += u.input;
1378
+ b.tokens.output += u.output;
1379
+ b.tokens.cacheRead += u.cacheRead;
1380
+ b.tokens.cacheWrite += u.cacheWrite;
1381
+ }
1299
1382
  }
1300
1383
  }
1301
1384
  }
@@ -1319,6 +1402,7 @@ function parseTranscript(rawLines) {
1319
1402
  lastAgentPreview,
1320
1403
  toolCallCount,
1321
1404
  turnCount,
1405
+ dailyBreakdown: Array.from(perDay.entries()).map(([day2, v]) => ({ day: day2, toolCalls: v.toolCalls, turns: v.turns, tokens: v.tokens })).sort((a, b) => a.day.localeCompare(b.day)),
1322
1406
  airTimeMs,
1323
1407
  activeSegments,
1324
1408
  linesAdded,
@@ -1337,6 +1421,7 @@ var init_parser = __esm({
1337
1421
  "../parser/dist/parser.js"() {
1338
1422
  "use strict";
1339
1423
  init_user_input();
1424
+ init_analytics();
1340
1425
  BLANK_USAGE2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
1341
1426
  TEAMMATE_MSG_RE = /^\s*<teammate-message\s+teammate_id="([^"]+)"[^>]*>([\s\S]*?)<\/teammate-message>/;
1342
1427
  }
@@ -1610,7 +1695,7 @@ async function loadCalibrationEvents(root = DEFAULT_ROOT) {
1610
1695
  out.sort((a, b) => a.ts.localeCompare(b.ts));
1611
1696
  return out;
1612
1697
  }
1613
- function aggregateUsageFromLines(lines, seenKeys, usage2) {
1698
+ function aggregateUsageFromLines(lines, seenKeys, usage2, perDay, fallbackDay) {
1614
1699
  for (const raw of lines) {
1615
1700
  if (!raw || typeof raw !== "object")
1616
1701
  continue;
@@ -1630,35 +1715,131 @@ function aggregateUsageFromLines(lines, seenKeys, usage2) {
1630
1715
  const u = m.usage;
1631
1716
  if (u) {
1632
1717
  const toNum = (v) => typeof v === "number" ? v : 0;
1633
- usage2.input += toNum(u.input_tokens);
1634
- usage2.output += toNum(u.output_tokens);
1635
- usage2.cacheRead += toNum(u.cache_read_input_tokens);
1636
- usage2.cacheWrite += toNum(u.cache_creation_input_tokens);
1718
+ const inp = toNum(u.input_tokens);
1719
+ const out = toNum(u.output_tokens);
1720
+ const cr = toNum(u.cache_read_input_tokens);
1721
+ const cw = toNum(u.cache_creation_input_tokens);
1722
+ usage2.input += inp;
1723
+ usage2.output += out;
1724
+ usage2.cacheRead += cr;
1725
+ usage2.cacheWrite += cw;
1726
+ if (perDay) {
1727
+ let day2;
1728
+ const ts = typeof r.timestamp === "string" ? r.timestamp : void 0;
1729
+ if (ts) {
1730
+ const ms = Date.parse(ts);
1731
+ if (!Number.isNaN(ms))
1732
+ day2 = toLocalDay(ms);
1733
+ }
1734
+ day2 = day2 ?? fallbackDay;
1735
+ if (day2) {
1736
+ let d = perDay.get(day2);
1737
+ if (!d) {
1738
+ d = { ...BLANK_USAGE3 };
1739
+ perDay.set(day2, d);
1740
+ }
1741
+ d.input += inp;
1742
+ d.output += out;
1743
+ d.cacheRead += cr;
1744
+ d.cacheWrite += cw;
1745
+ }
1746
+ }
1637
1747
  }
1638
1748
  }
1639
1749
  }
1640
- async function computeSessionUsageWithSubagents(parentLines, projectDirPath, sessionId) {
1750
+ async function computeSessionUsageWithSubagents(parentLines, projectDirPath, sessionId, fallbackDay) {
1641
1751
  const usage2 = { ...BLANK_USAGE3 };
1642
1752
  const seenKeys = /* @__PURE__ */ new Set();
1643
- aggregateUsageFromLines(parentLines, seenKeys, usage2);
1753
+ const perDay = /* @__PURE__ */ new Map();
1754
+ aggregateUsageFromLines(parentLines, seenKeys, usage2, perDay, fallbackDay);
1644
1755
  const subagentsDir = path.join(projectDirPath, sessionId, "subagents");
1645
1756
  let entries2;
1646
1757
  try {
1647
1758
  entries2 = await fs.readdir(subagentsDir);
1648
1759
  } catch {
1649
- return usage2;
1760
+ return { usage: usage2, perDay };
1650
1761
  }
1651
1762
  const jsonlFiles = entries2.filter((f) => f.endsWith(".jsonl"));
1652
1763
  if (jsonlFiles.length === 0)
1653
- return usage2;
1764
+ return { usage: usage2, perDay };
1654
1765
  await Promise.all(jsonlFiles.map(async (f) => {
1655
1766
  try {
1656
1767
  const lines = await readJsonlFile(path.join(subagentsDir, f));
1657
- aggregateUsageFromLines(lines, seenKeys, usage2);
1768
+ aggregateUsageFromLines(lines, seenKeys, usage2, perDay, fallbackDay);
1658
1769
  } catch {
1659
1770
  }
1660
1771
  }));
1661
- return usage2;
1772
+ return { usage: usage2, perDay };
1773
+ }
1774
+ function mergeDailyTokens(base, perDayTokens, totalUsage) {
1775
+ const counts = new Map((base ?? []).map((d) => [d.day, d]));
1776
+ const days = /* @__PURE__ */ new Set([...counts.keys(), ...perDayTokens.keys()]);
1777
+ const out = [...days].sort((a, b) => a.localeCompare(b)).map((day2) => ({
1778
+ day: day2,
1779
+ toolCalls: counts.get(day2)?.toolCalls ?? 0,
1780
+ turns: counts.get(day2)?.turns ?? 0,
1781
+ tokens: { ...perDayTokens.get(day2) ?? BLANK_USAGE3 }
1782
+ }));
1783
+ if (out.length > 0) {
1784
+ const summed = out.reduce((a, r) => ({
1785
+ input: a.input + r.tokens.input,
1786
+ output: a.output + r.tokens.output,
1787
+ cacheRead: a.cacheRead + r.tokens.cacheRead,
1788
+ cacheWrite: a.cacheWrite + r.tokens.cacheWrite
1789
+ }), { ...BLANK_USAGE3 });
1790
+ const first = out[0].tokens;
1791
+ first.input += totalUsage.input - summed.input;
1792
+ first.output += totalUsage.output - summed.output;
1793
+ first.cacheRead += totalUsage.cacheRead - summed.cacheRead;
1794
+ first.cacheWrite += totalUsage.cacheWrite - summed.cacheWrite;
1795
+ }
1796
+ return out;
1797
+ }
1798
+ async function scanWorkflowAggregate(projectDirPath, sessionId) {
1799
+ const dir = path.join(projectDirPath, sessionId, "workflows");
1800
+ let entries2;
1801
+ try {
1802
+ entries2 = await fs.readdir(dir);
1803
+ } catch {
1804
+ return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
1805
+ }
1806
+ const jsonFiles = entries2.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
1807
+ if (jsonFiles.length === 0)
1808
+ return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
1809
+ let spawnedAgentCount = 0;
1810
+ const spans = [];
1811
+ const parsed = await Promise.all(jsonFiles.map(async (f) => {
1812
+ try {
1813
+ const j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
1814
+ if (typeof j.agentCount === "number")
1815
+ spawnedAgentCount += j.agentCount;
1816
+ if (typeof j.startTime === "number" && typeof j.durationMs === "number" && j.durationMs > 0) {
1817
+ spans.push({ startMs: j.startTime, endMs: j.startTime + j.durationMs });
1818
+ }
1819
+ return true;
1820
+ } catch {
1821
+ return false;
1822
+ }
1823
+ }));
1824
+ return { workflowCount: parsed.filter(Boolean).length, spawnedAgentCount, spans };
1825
+ }
1826
+ function foldWorkflowAgentTime(activeSegments, spans) {
1827
+ if (spans.length === 0)
1828
+ return {};
1829
+ const all = [...activeSegments ?? [], ...spans].filter((s) => s.endMs > s.startMs).sort((a, b) => a.startMs - b.startMs);
1830
+ if (all.length === 0)
1831
+ return {};
1832
+ const merged = [{ ...all[0] }];
1833
+ for (let i = 1; i < all.length; i++) {
1834
+ const cur = all[i];
1835
+ const last = merged[merged.length - 1];
1836
+ if (cur.startMs <= last.endMs)
1837
+ last.endMs = Math.max(last.endMs, cur.endMs);
1838
+ else
1839
+ merged.push({ ...cur });
1840
+ }
1841
+ const airTimeMs = merged.reduce((n, s) => n + (s.endMs - s.startMs), 0);
1842
+ return { activeSegments: merged, airTimeMs };
1662
1843
  }
1663
1844
  async function getCachedMeta(f) {
1664
1845
  const cached = metaCache.get(f.fullPath);
@@ -1670,13 +1851,19 @@ async function getCachedMeta(f) {
1670
1851
  const { meta } = parseTranscript(rawLines);
1671
1852
  const sessionId = sessionIdFromFileName(f.fileName);
1672
1853
  const projectDirPath = path.dirname(f.fullPath);
1673
- meta.totalUsage = await computeSessionUsageWithSubagents(rawLines, projectDirPath, sessionId);
1854
+ const fallbackDay = meta.firstTimestamp ? toLocalDay(Date.parse(meta.firstTimestamp)) : void 0;
1855
+ const { usage: usage2, perDay: perDayTokens } = await computeSessionUsageWithSubagents(rawLines, projectDirPath, sessionId, fallbackDay);
1856
+ meta.totalUsage = usage2;
1857
+ meta.dailyBreakdown = mergeDailyTokens(meta.dailyBreakdown, perDayTokens, usage2);
1858
+ const wf = await scanWorkflowAggregate(projectDirPath, sessionId);
1674
1859
  const full = {
1675
1860
  ...meta,
1676
1861
  id: sessionId,
1677
1862
  filePath: f.fullPath,
1678
1863
  projectDir: f.projectDir,
1679
- projectName: meta.cwd ?? decodeProjectName(f.projectDir)
1864
+ projectName: meta.cwd ?? decodeProjectName(f.projectDir),
1865
+ ...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
1866
+ ...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
1680
1867
  };
1681
1868
  metaCache.set(f.fullPath, { meta: full, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
1682
1869
  return full;
@@ -1692,13 +1879,17 @@ async function getCachedDetail(f) {
1692
1879
  try {
1693
1880
  const rawLines = await readJsonlFile(f.fullPath);
1694
1881
  const { meta, events } = parseTranscript(rawLines);
1882
+ const sessionId = sessionIdFromFileName(f.fileName);
1883
+ const wf = await scanWorkflowAggregate(path.dirname(f.fullPath), sessionId);
1695
1884
  const detail = {
1696
1885
  ...meta,
1697
- id: sessionIdFromFileName(f.fileName),
1886
+ id: sessionId,
1698
1887
  filePath: f.fullPath,
1699
1888
  projectDir: f.projectDir,
1700
1889
  projectName: meta.cwd ?? decodeProjectName(f.projectDir),
1701
- events
1890
+ events,
1891
+ ...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
1892
+ ...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
1702
1893
  };
1703
1894
  detailCache.set(f.fullPath, { detail, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
1704
1895
  const metaOnly = { ...detail };
@@ -1730,8 +1921,18 @@ async function getSession(id, opts = {}) {
1730
1921
  return detail;
1731
1922
  const sessionStartMs = detail.firstTimestamp ? Date.parse(detail.firstTimestamp) : void 0;
1732
1923
  const subagentsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "subagents");
1733
- const subagents = await loadSubagents(subagentsDir, sessionStartMs, detail.events);
1734
- return { ...detail, subagents };
1924
+ const workflowsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "workflows");
1925
+ const [subagents, workflows] = await Promise.all([
1926
+ loadSubagents(subagentsDir, sessionStartMs, detail.events),
1927
+ loadWorkflows(workflowsDir, sessionStartMs, detail.events)
1928
+ ]);
1929
+ const spawnedAgentCount = workflows.reduce((n, w) => n + w.agentCount, 0);
1930
+ return {
1931
+ ...detail,
1932
+ subagents,
1933
+ workflows,
1934
+ ...workflows.length > 0 ? { workflowCount: workflows.length, spawnedAgentCount } : {}
1935
+ };
1735
1936
  }
1736
1937
  function summarizeSubagentLines(lines) {
1737
1938
  let startMs;
@@ -1921,6 +2122,248 @@ async function loadSubagents(dir, sessionStartMs, parentEvents) {
1921
2122
  }));
1922
2123
  return runs2.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
1923
2124
  }
2125
+ async function loadWorkflows(dir, sessionStartMs, parentEvents) {
2126
+ let entries2;
2127
+ try {
2128
+ entries2 = await fs.readdir(dir);
2129
+ } catch {
2130
+ return [];
2131
+ }
2132
+ const jsonFiles = entries2.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
2133
+ if (jsonFiles.length === 0)
2134
+ return [];
2135
+ const dispatches = [];
2136
+ for (const e of parentEvents) {
2137
+ if (e.role !== "tool-call" || e.toolName !== "Workflow")
2138
+ continue;
2139
+ const tsMs = e.timestamp ? Date.parse(e.timestamp) : NaN;
2140
+ if (Number.isNaN(tsMs))
2141
+ continue;
2142
+ for (const b of e.blocks) {
2143
+ if (b?.type !== "tool_use" || b.name !== "Workflow")
2144
+ continue;
2145
+ dispatches.push({ toolUseId: b.id, parentUuid: e.uuid ?? "", tsMs });
2146
+ }
2147
+ }
2148
+ dispatches.sort((a, b) => a.tsMs - b.tsMs);
2149
+ const matchDispatch = (startMs) => {
2150
+ if (startMs === void 0 || dispatches.length === 0)
2151
+ return void 0;
2152
+ const TOLERANCE_MS = 6e4;
2153
+ let before;
2154
+ let beforeDelta = Infinity;
2155
+ let nearest;
2156
+ let nearestDelta = Infinity;
2157
+ for (const d of dispatches) {
2158
+ const delta = Math.abs(startMs - d.tsMs);
2159
+ if (delta > TOLERANCE_MS)
2160
+ continue;
2161
+ if (delta < nearestDelta) {
2162
+ nearest = d;
2163
+ nearestDelta = delta;
2164
+ }
2165
+ if (d.tsMs <= startMs && delta < beforeDelta) {
2166
+ before = d;
2167
+ beforeDelta = delta;
2168
+ }
2169
+ }
2170
+ return before ?? nearest;
2171
+ };
2172
+ const num2 = (v) => typeof v === "number" ? v : void 0;
2173
+ const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
2174
+ const runs2 = await Promise.all(jsonFiles.map(async (f) => {
2175
+ let j;
2176
+ try {
2177
+ j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
2178
+ } catch {
2179
+ return null;
2180
+ }
2181
+ const runId = str(j.runId) ?? f.replace(/\.json$/, "");
2182
+ const startMs = num2(j.startTime);
2183
+ const durationMs = num2(j.durationMs);
2184
+ const endMs = startMs !== void 0 && durationMs !== void 0 ? startMs + durationMs : void 0;
2185
+ const startTOffsetMs = sessionStartMs !== void 0 && startMs !== void 0 ? Math.max(0, startMs - sessionStartMs) : void 0;
2186
+ const endTOffsetMs = sessionStartMs !== void 0 && endMs !== void 0 ? Math.max(0, endMs - sessionStartMs) : void 0;
2187
+ const phases = Array.isArray(j.phases) ? j.phases.filter((p) => !!p && typeof p === "object" && typeof p.title === "string").map((p) => ({ title: p.title, detail: str(p.detail) })) : [];
2188
+ const logs = Array.isArray(j.logs) ? j.logs.filter((l) => typeof l === "string") : [];
2189
+ const cap = (v, n) => {
2190
+ const s = str(v);
2191
+ return s === void 0 ? void 0 : s.length > n ? s.slice(0, n) + "\u2026" : s;
2192
+ };
2193
+ const progress = Array.isArray(j.workflowProgress) ? j.workflowProgress : [];
2194
+ const agents = progress.filter((e) => !!e && typeof e === "object" && e.type === "workflow_agent").map((e) => ({
2195
+ index: num2(e.index) ?? 0,
2196
+ label: str(e.label) ?? "(agent)",
2197
+ phaseIndex: num2(e.phaseIndex),
2198
+ phaseTitle: str(e.phaseTitle),
2199
+ agentId: str(e.agentId),
2200
+ model: str(e.model),
2201
+ state: str(e.state),
2202
+ startedAt: num2(e.startedAt),
2203
+ durationMs: num2(e.durationMs),
2204
+ tokens: num2(e.tokens),
2205
+ toolCalls: num2(e.toolCalls),
2206
+ lastToolSummary: cap(e.lastToolSummary, 200),
2207
+ promptPreview: cap(e.promptPreview, 600),
2208
+ resultPreview: cap(e.resultPreview, 600)
2209
+ })).sort((a, b) => a.index - b.index);
2210
+ const parent = matchDispatch(startMs);
2211
+ return {
2212
+ runId,
2213
+ name: str(j.workflowName) ?? runId,
2214
+ description: str(j.summary),
2215
+ status: str(j.status) ?? "unknown",
2216
+ agentCount: num2(j.agentCount) ?? 0,
2217
+ toolCallCount: num2(j.totalToolCalls) ?? 0,
2218
+ totalTokens: num2(j.totalTokens) ?? 0,
2219
+ durationMs,
2220
+ startMs,
2221
+ endMs,
2222
+ startTOffsetMs,
2223
+ endTOffsetMs,
2224
+ model: str(j.defaultModel),
2225
+ phases,
2226
+ logs,
2227
+ agents,
2228
+ parentToolUseId: parent?.toolUseId,
2229
+ parentUuid: parent?.parentUuid
2230
+ };
2231
+ }));
2232
+ return runs2.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
2233
+ }
2234
+ function salientToolInput(input) {
2235
+ if (!input || typeof input !== "object")
2236
+ return "";
2237
+ const o = input;
2238
+ const pick = (k) => typeof o[k] === "string" ? o[k] : void 0;
2239
+ return pick("command") ?? pick("file_path") ?? pick("path") ?? pick("pattern") ?? pick("url") ?? pick("description") ?? pick("query") ?? pick("prompt") ?? pick("old_string") ?? JSON.stringify(o);
2240
+ }
2241
+ async function loadWorkflowAgentDetail(sessionId, runId, agentId, opts = {}) {
2242
+ const { root = DEFAULT_ROOT } = opts;
2243
+ if (!/^[\w.-]+$/.test(runId) || !/^[\w.-]+$/.test(agentId))
2244
+ return null;
2245
+ const files = await walkJsonlFiles(root);
2246
+ const hit = files.find((f) => sessionIdFromFileName(f.fileName) === sessionId);
2247
+ if (!hit)
2248
+ return null;
2249
+ const file = path.join(path.dirname(hit.fullPath), sessionId, "subagents", "workflows", runId, `agent-${agentId}.jsonl`);
2250
+ let lines;
2251
+ try {
2252
+ lines = await readJsonlFile(file);
2253
+ } catch {
2254
+ return null;
2255
+ }
2256
+ const errored = /* @__PURE__ */ new Set();
2257
+ for (const raw of lines) {
2258
+ if (!raw || typeof raw !== "object")
2259
+ continue;
2260
+ const content = raw.message?.content;
2261
+ if (!Array.isArray(content))
2262
+ continue;
2263
+ for (const b of content) {
2264
+ if (b && typeof b === "object" && b.type === "tool_result" && b.is_error === true && typeof b.tool_use_id === "string") {
2265
+ errored.add(b.tool_use_id);
2266
+ }
2267
+ }
2268
+ }
2269
+ const steps = [];
2270
+ const toolCounts = /* @__PURE__ */ new Map();
2271
+ const totalUsage = { ...BLANK_USAGE3 };
2272
+ const seen = /* @__PURE__ */ new Set();
2273
+ let prompt;
2274
+ let finalText;
2275
+ let model;
2276
+ let assistantMessageCount = 0;
2277
+ let eventCount = 0;
2278
+ let startMs;
2279
+ let endMs;
2280
+ for (const raw of lines) {
2281
+ if (!raw || typeof raw !== "object")
2282
+ continue;
2283
+ const r = raw;
2284
+ eventCount++;
2285
+ const ts = typeof r.timestamp === "string" ? Date.parse(r.timestamp) : NaN;
2286
+ if (!Number.isNaN(ts)) {
2287
+ if (startMs === void 0 || ts < startMs)
2288
+ startMs = ts;
2289
+ if (endMs === void 0 || ts > endMs)
2290
+ endMs = ts;
2291
+ }
2292
+ if (prompt === void 0 && r.type === "user" && (r.parentUuid === null || r.parentUuid === void 0)) {
2293
+ const c = r.message?.content;
2294
+ if (typeof c === "string")
2295
+ prompt = c;
2296
+ else if (Array.isArray(c)) {
2297
+ const t = c.find((b) => b && typeof b === "object" && b.type === "text");
2298
+ if (t?.text)
2299
+ prompt = t.text;
2300
+ }
2301
+ }
2302
+ if (r.type !== "assistant")
2303
+ continue;
2304
+ const m = r.message;
2305
+ if (!m)
2306
+ continue;
2307
+ if (!model && typeof m.model === "string")
2308
+ model = m.model;
2309
+ const mid = typeof m.id === "string" ? m.id : void 0;
2310
+ const rid = typeof r.requestId === "string" ? r.requestId : void 0;
2311
+ const key = mid != null && rid != null ? `${mid}:${rid}` : void 0;
2312
+ const fresh = key ? !seen.has(key) : true;
2313
+ if (key && fresh)
2314
+ seen.add(key);
2315
+ if (fresh) {
2316
+ assistantMessageCount++;
2317
+ const u = m.usage;
2318
+ if (u) {
2319
+ const n = (v) => typeof v === "number" ? v : 0;
2320
+ totalUsage.input += n(u.input_tokens);
2321
+ totalUsage.output += n(u.output_tokens);
2322
+ totalUsage.cacheRead += n(u.cache_read_input_tokens);
2323
+ totalUsage.cacheWrite += n(u.cache_creation_input_tokens);
2324
+ }
2325
+ }
2326
+ const content = m.content;
2327
+ if (!Array.isArray(content))
2328
+ continue;
2329
+ for (const b of content) {
2330
+ if (!b || typeof b !== "object")
2331
+ continue;
2332
+ if (b.type === "text" && typeof b.text === "string") {
2333
+ finalText = b.text;
2334
+ } else if (b.type === "tool_use" && typeof b.name === "string") {
2335
+ toolCounts.set(b.name, (toolCounts.get(b.name) ?? 0) + 1);
2336
+ if (steps.length < 2e3) {
2337
+ const salient = salientToolInput(b.input);
2338
+ const preview = salient.replace(/\s+/g, " ").trim().slice(0, 160);
2339
+ const full = salient.length > 4e3 ? salient.slice(0, 4e3) + "\u2026" : salient;
2340
+ steps.push({
2341
+ index: steps.length + 1,
2342
+ tool: b.name,
2343
+ preview,
2344
+ // Only carry `full` when it adds something over the one-line preview.
2345
+ full: full.length > preview.length || full.includes("\n") ? full : void 0,
2346
+ isError: typeof b.id === "string" && errored.has(b.id)
2347
+ });
2348
+ }
2349
+ }
2350
+ }
2351
+ }
2352
+ const toolCalls = Array.from(toolCounts.entries()).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
2353
+ return {
2354
+ agentId,
2355
+ prompt,
2356
+ finalText,
2357
+ steps,
2358
+ toolCalls,
2359
+ toolCallCount: steps.length,
2360
+ assistantMessageCount,
2361
+ eventCount,
2362
+ totalUsage,
2363
+ model,
2364
+ durationMs: startMs !== void 0 && endMs !== void 0 ? endMs - startMs : void 0
2365
+ };
2366
+ }
1924
2367
  async function listProjects(root = DEFAULT_ROOT) {
1925
2368
  const files = await walkJsonlFiles(root);
1926
2369
  const byRawDir = /* @__PURE__ */ new Map();
@@ -1942,10 +2385,10 @@ async function listProjects(root = DEFAULT_ROOT) {
1942
2385
  const canonicalMap = /* @__PURE__ */ new Map();
1943
2386
  for (const [rawDir, { count, lastActiveMs }] of byRawDir) {
1944
2387
  const cwdOrDecoded = cwdForProject(rawDir) ?? decodeProjectName(rawDir);
1945
- const canonical = canonicalProjectName(cwdOrDecoded);
2388
+ const repo = projectRepoName(cwdOrDecoded);
1946
2389
  const wt = worktreeName(cwdOrDecoded);
1947
- const agg = canonicalMap.get(canonical) ?? {
1948
- canonicalName: canonical,
2390
+ const agg = canonicalMap.get(repo) ?? {
2391
+ canonicalName: repo,
1949
2392
  count: 0,
1950
2393
  lastActiveMs: 0,
1951
2394
  worktreeBranches: /* @__PURE__ */ new Set()
@@ -1955,7 +2398,7 @@ async function listProjects(root = DEFAULT_ROOT) {
1955
2398
  agg.lastActiveMs = lastActiveMs;
1956
2399
  if (wt)
1957
2400
  agg.worktreeBranches.add(wt);
1958
- canonicalMap.set(canonical, agg);
2401
+ canonicalMap.set(repo, agg);
1959
2402
  }
1960
2403
  return Array.from(canonicalMap.values()).map((a) => ({
1961
2404
  projectDir: a.canonicalName,
@@ -2919,11 +3362,404 @@ async function listGeminiSessions(opts = {}) {
2919
3362
  continue;
2920
3363
  }
2921
3364
  try {
2922
- const { meta } = await parseSession(file);
2923
- metaCache3.set(file.filePath, {
3365
+ const { meta } = await parseSession(file);
3366
+ metaCache3.set(file.filePath, {
3367
+ meta,
3368
+ mtimeMs: file.mtimeMs,
3369
+ sizeBytes: file.sizeBytes
3370
+ });
3371
+ out.push(meta);
3372
+ } catch {
3373
+ }
3374
+ }
3375
+ out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
3376
+ if (opts.limit !== void 0)
3377
+ return out.slice(0, opts.limit);
3378
+ return out;
3379
+ }
3380
+ async function getGeminiSession(id, opts = {}) {
3381
+ const root = opts.root ?? DEFAULT_GEMINI_ROOT;
3382
+ const files = await listSessionFiles(root);
3383
+ let chosen;
3384
+ for (const file of files) {
3385
+ if (file.filenameId === id || id.startsWith(file.filenameId)) {
3386
+ chosen = file;
3387
+ break;
3388
+ }
3389
+ }
3390
+ if (!chosen) {
3391
+ for (const file of files) {
3392
+ const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
3393
+ if (meta2.id === id) {
3394
+ chosen = file;
3395
+ break;
3396
+ }
3397
+ }
3398
+ }
3399
+ if (!chosen)
3400
+ return null;
3401
+ const cached = detailCache3.get(chosen.filePath);
3402
+ if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
3403
+ return cached.detail;
3404
+ }
3405
+ const { meta, events } = await parseSession(chosen);
3406
+ const detail = { ...meta, events };
3407
+ detailCache3.set(chosen.filePath, {
3408
+ detail,
3409
+ mtimeMs: chosen.mtimeMs,
3410
+ sizeBytes: chosen.sizeBytes
3411
+ });
3412
+ return detail;
3413
+ }
3414
+ function geminiSessionLocalDay(meta) {
3415
+ if (!meta.firstTimestamp)
3416
+ return void 0;
3417
+ const ms = Date.parse(meta.firstTimestamp);
3418
+ return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
3419
+ }
3420
+ var DEFAULT_GEMINI_ROOT, GEMINI_PROJECTS_FILE, SESSION_FILE_RE, IDLE_GAP_MS2, projectsCache, metaCache3, detailCache3;
3421
+ var init_gemini = __esm({
3422
+ "../parser/dist/gemini.js"() {
3423
+ "use strict";
3424
+ init_analytics();
3425
+ init_user_input();
3426
+ DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
3427
+ GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
3428
+ SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
3429
+ IDLE_GAP_MS2 = 3 * 60 * 1e3;
3430
+ projectsCache = null;
3431
+ metaCache3 = /* @__PURE__ */ new Map();
3432
+ detailCache3 = /* @__PURE__ */ new Map();
3433
+ }
3434
+ });
3435
+
3436
+ // ../parser/dist/antigravity.js
3437
+ import { promises as fs4 } from "node:fs";
3438
+ import os4 from "node:os";
3439
+ import path4 from "node:path";
3440
+ async function safeReaddir3(p) {
3441
+ return fs4.readdir(p).catch(() => []);
3442
+ }
3443
+ async function loadSlugToCwd2(root) {
3444
+ const historyFile = path4.join(root, "history.jsonl");
3445
+ const stat = await fs4.stat(historyFile).catch(() => null);
3446
+ if (!stat)
3447
+ return /* @__PURE__ */ new Map();
3448
+ if (historyCache && historyCache.mtimeMs === stat.mtimeMs) {
3449
+ return historyCache.slugToCwd;
3450
+ }
3451
+ const raw = await fs4.readFile(historyFile, "utf8").catch(() => "");
3452
+ const slugToCwd = /* @__PURE__ */ new Map();
3453
+ for (const line of raw.split("\n")) {
3454
+ const trimmed = line.trim();
3455
+ if (!trimmed)
3456
+ continue;
3457
+ try {
3458
+ const parsed = JSON.parse(trimmed);
3459
+ if (parsed.conversationId && parsed.workspace) {
3460
+ slugToCwd.set(parsed.conversationId, parsed.workspace);
3461
+ }
3462
+ } catch {
3463
+ }
3464
+ }
3465
+ historyCache = { mtimeMs: stat.mtimeMs, slugToCwd };
3466
+ return slugToCwd;
3467
+ }
3468
+ async function listSessionFiles2(root) {
3469
+ const slugToCwd = await loadSlugToCwd2(root);
3470
+ const out = [];
3471
+ const brainDir = path4.join(root, "brain");
3472
+ const entries2 = await safeReaddir3(brainDir);
3473
+ for (const entry of entries2) {
3474
+ const transcriptPath = path4.join(brainDir, entry, ".system_generated", "logs", "transcript.jsonl");
3475
+ const stat = await fs4.stat(transcriptPath).catch(() => null);
3476
+ if (stat && stat.isFile()) {
3477
+ out.push({
3478
+ filePath: transcriptPath,
3479
+ conversationId: entry,
3480
+ cwd: slugToCwd.get(entry),
3481
+ mtimeMs: stat.mtimeMs,
3482
+ sizeBytes: stat.size
3483
+ });
3484
+ }
3485
+ }
3486
+ return out;
3487
+ }
3488
+ function emptyUsage3() {
3489
+ return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
3490
+ }
3491
+ function previewOf3(text) {
3492
+ return text.replace(/\s+/g, " ").trim().slice(0, 200);
3493
+ }
3494
+ function truncate4(s, n) {
3495
+ return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
3496
+ }
3497
+ async function parseSession2(file) {
3498
+ const raw = await fs4.readFile(file.filePath, "utf8");
3499
+ const events = [];
3500
+ const totalUsage = emptyUsage3();
3501
+ let firstTimestamp;
3502
+ let lastTimestamp;
3503
+ let model;
3504
+ let toolCallCount = 0;
3505
+ let turnCount = 0;
3506
+ let firstUserPreview;
3507
+ let lastUserPreview;
3508
+ let lastAgentPreview;
3509
+ const tsMs = [];
3510
+ let idx = 0;
3511
+ function pushEvent(e) {
3512
+ events.push(e);
3513
+ if (e.timestamp && e.role !== "meta") {
3514
+ if (!firstTimestamp)
3515
+ firstTimestamp = e.timestamp;
3516
+ lastTimestamp = e.timestamp;
3517
+ const ms = Date.parse(e.timestamp);
3518
+ if (Number.isFinite(ms))
3519
+ tsMs.push(ms);
3520
+ }
3521
+ }
3522
+ const pendingToolCalls = [];
3523
+ const parsedObjects = [];
3524
+ const indexMap = /* @__PURE__ */ new Map();
3525
+ for (const line of raw.split("\n")) {
3526
+ const trimmed = line.trim();
3527
+ if (!trimmed)
3528
+ continue;
3529
+ try {
3530
+ const obj = JSON.parse(trimmed);
3531
+ const stepIdx = obj.step_index;
3532
+ if (typeof stepIdx === "number") {
3533
+ if (indexMap.has(stepIdx)) {
3534
+ parsedObjects[indexMap.get(stepIdx)] = obj;
3535
+ } else {
3536
+ indexMap.set(stepIdx, parsedObjects.length);
3537
+ parsedObjects.push(obj);
3538
+ }
3539
+ } else {
3540
+ parsedObjects.push(obj);
3541
+ }
3542
+ } catch {
3543
+ }
3544
+ }
3545
+ for (const eventObj of parsedObjects) {
3546
+ const ts = eventObj.created_at || eventObj.timestamp;
3547
+ if (eventObj.type === "USER_INPUT") {
3548
+ if (typeof eventObj.content === "string") {
3549
+ const matchNoNeed = eventObj.content.match(/Model Selection` from .*? to (.*?)\.\s*No need to/);
3550
+ if (matchNoNeed) {
3551
+ let rawModel = matchNoNeed[1].trim();
3552
+ rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
3553
+ model = rawModel;
3554
+ } else {
3555
+ const matchDot = eventObj.content.match(/Model Selection` from .*? to ([^\n]+)/);
3556
+ if (matchDot) {
3557
+ let rawModel = matchDot[1].trim();
3558
+ if (rawModel.endsWith(".")) {
3559
+ rawModel = rawModel.slice(0, -1).trim();
3560
+ }
3561
+ rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
3562
+ model = rawModel;
3563
+ }
3564
+ }
3565
+ }
3566
+ let text2 = eventObj.content || "";
3567
+ const requestMatch = text2.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
3568
+ if (requestMatch) {
3569
+ text2 = requestMatch[1].trim();
3570
+ }
3571
+ const preview = previewOf3(text2);
3572
+ const isHidden = isFrameworkInjectedUserInput(text2);
3573
+ if (text2 && !isHidden) {
3574
+ if (!firstUserPreview)
3575
+ firstUserPreview = preview;
3576
+ lastUserPreview = preview;
3577
+ turnCount += 1;
3578
+ }
3579
+ pushEvent({
3580
+ index: idx++,
3581
+ timestamp: ts,
3582
+ role: "user",
3583
+ rawType: "antigravity/user",
3584
+ preview,
3585
+ blocks: text2 ? [{ type: "text", text: text2 }] : [],
3586
+ messageId: eventObj.step_index?.toString(),
3587
+ raw: eventObj
3588
+ });
3589
+ continue;
3590
+ }
3591
+ if (eventObj.type === "PLANNER_RESPONSE") {
3592
+ const thinking = eventObj.thinking;
3593
+ const content = eventObj.content;
3594
+ if (thinking) {
3595
+ pushEvent({
3596
+ index: idx++,
3597
+ timestamp: ts,
3598
+ role: "agent-thinking",
3599
+ rawType: "antigravity/thought",
3600
+ preview: previewOf3(thinking),
3601
+ blocks: [{ type: "thinking", thinking }],
3602
+ model,
3603
+ raw: eventObj
3604
+ });
3605
+ }
3606
+ if (content) {
3607
+ const preview = previewOf3(content);
3608
+ lastAgentPreview = preview;
3609
+ pushEvent({
3610
+ index: idx++,
3611
+ timestamp: ts,
3612
+ role: "agent",
3613
+ rawType: "antigravity/agent",
3614
+ preview,
3615
+ blocks: [{ type: "text", text: content }],
3616
+ messageId: eventObj.step_index?.toString(),
3617
+ model,
3618
+ raw: eventObj
3619
+ });
3620
+ }
3621
+ const toolCalls = eventObj.tool_calls || [];
3622
+ for (let cIdx = 0; cIdx < toolCalls.length; cIdx++) {
3623
+ const tc = toolCalls[cIdx];
3624
+ toolCallCount += 1;
3625
+ const toolUseId = `tool-${eventObj.step_index}-${cIdx}`;
3626
+ const argsStr = tc.args ? JSON.stringify(tc.args) : "";
3627
+ pendingToolCalls.push({ id: toolUseId, name: tc.name });
3628
+ pushEvent({
3629
+ index: idx++,
3630
+ timestamp: ts,
3631
+ role: "tool-call",
3632
+ rawType: "antigravity/tool_call",
3633
+ preview: `${tc.name}(${truncate4(argsStr, 80)})`,
3634
+ blocks: [{ type: "tool_use", id: toolUseId, name: tc.name, input: tc.args || {} }],
3635
+ toolName: tc.name,
3636
+ toolUseId,
3637
+ model,
3638
+ raw: tc
3639
+ });
3640
+ }
3641
+ continue;
3642
+ }
3643
+ if (eventObj.source === "MODEL" && eventObj.type !== "PLANNER_RESPONSE" && eventObj.type !== "ERROR_MESSAGE" && pendingToolCalls.length > 0) {
3644
+ const matchedCall = pendingToolCalls.shift();
3645
+ const toolUseId = matchedCall ? matchedCall.id : `tool-${eventObj.step_index}-unknown`;
3646
+ const contentStr = typeof eventObj.content === "string" ? eventObj.content : JSON.stringify(eventObj.content || "");
3647
+ const isError = eventObj.status === "ERROR" || eventObj.status === "FAILED" || eventObj.status === "CANCELED" || !!eventObj.error;
3648
+ pushEvent({
3649
+ index: idx++,
3650
+ timestamp: ts,
3651
+ role: "tool-result",
3652
+ rawType: "antigravity/tool_result",
3653
+ preview: previewOf3(contentStr),
3654
+ blocks: [{
3655
+ type: "tool_result",
3656
+ tool_use_id: toolUseId,
3657
+ content: contentStr,
3658
+ is_error: isError
3659
+ }],
3660
+ toolUseId,
3661
+ toolResult: contentStr,
3662
+ raw: eventObj
3663
+ });
3664
+ continue;
3665
+ }
3666
+ const text = eventObj.content || eventObj.error || "";
3667
+ pushEvent({
3668
+ index: idx++,
3669
+ timestamp: ts,
3670
+ role: "meta",
3671
+ rawType: `antigravity/${eventObj.type?.toLowerCase() || "unknown"}`,
3672
+ preview: previewOf3(text),
3673
+ blocks: text ? [{ type: "text", text }] : [],
3674
+ raw: eventObj
3675
+ });
3676
+ }
3677
+ const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
3678
+ if (startMs !== void 0 && Number.isFinite(startMs)) {
3679
+ let prevMs;
3680
+ for (const ev of events) {
3681
+ if (!ev.timestamp)
3682
+ continue;
3683
+ const ms = Date.parse(ev.timestamp);
3684
+ if (!Number.isFinite(ms))
3685
+ continue;
3686
+ ev.tOffsetMs = Math.max(0, ms - startMs);
3687
+ if (prevMs !== void 0)
3688
+ ev.gapMs = Math.max(0, ms - prevMs);
3689
+ prevMs = ms;
3690
+ }
3691
+ }
3692
+ const activeSegments = computeActiveSegments4(tsMs);
3693
+ const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
3694
+ const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
3695
+ const sessionId = file.conversationId;
3696
+ const cwd = file.cwd;
3697
+ const projectName = cwd ? canonicalProjectName(cwd) : file.conversationId;
3698
+ const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.conversationId;
3699
+ const meta = {
3700
+ agent: "antigravity",
3701
+ id: sessionId,
3702
+ filePath: file.filePath,
3703
+ projectName,
3704
+ projectDir,
3705
+ sessionId,
3706
+ firstTimestamp,
3707
+ lastTimestamp,
3708
+ durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
3709
+ eventCount: events.length,
3710
+ model,
3711
+ cwd,
3712
+ totalUsage,
3713
+ status: "idle",
3714
+ firstUserPreview,
3715
+ lastUserPreview,
3716
+ lastAgentPreview,
3717
+ toolCallCount,
3718
+ turnCount,
3719
+ airTimeMs,
3720
+ activeSegments
3721
+ };
3722
+ return { meta, events };
3723
+ }
3724
+ function computeActiveSegments4(tsMs) {
3725
+ if (tsMs.length === 0)
3726
+ return [];
3727
+ const sorted = [...tsMs].sort((a, b) => a - b);
3728
+ const out = [];
3729
+ let segStart = sorted[0];
3730
+ let segEnd = sorted[0];
3731
+ for (let i = 1; i < sorted.length; i++) {
3732
+ if (sorted[i] - segEnd > IDLE_GAP_MS3) {
3733
+ out.push({ startMs: segStart, endMs: segEnd });
3734
+ segStart = sorted[i];
3735
+ }
3736
+ segEnd = sorted[i];
3737
+ }
3738
+ out.push({ startMs: segStart, endMs: segEnd });
3739
+ return out;
3740
+ }
3741
+ function clearAntigravityCaches() {
3742
+ metaCache4.clear();
3743
+ detailCache4.clear();
3744
+ historyCache = null;
3745
+ }
3746
+ async function listAntigravitySessions(opts = {}) {
3747
+ const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
3748
+ const files = await listSessionFiles2(root);
3749
+ const out = [];
3750
+ for (const file of files) {
3751
+ const cached = metaCache4.get(file.filePath);
3752
+ if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes && cached.cwd === file.cwd) {
3753
+ out.push(cached.meta);
3754
+ continue;
3755
+ }
3756
+ try {
3757
+ const { meta } = await parseSession2(file);
3758
+ metaCache4.set(file.filePath, {
2924
3759
  meta,
2925
3760
  mtimeMs: file.mtimeMs,
2926
- sizeBytes: file.sizeBytes
3761
+ sizeBytes: file.sizeBytes,
3762
+ cwd: file.cwd
2927
3763
  });
2928
3764
  out.push(meta);
2929
3765
  } catch {
@@ -2934,59 +3770,274 @@ async function listGeminiSessions(opts = {}) {
2934
3770
  return out.slice(0, opts.limit);
2935
3771
  return out;
2936
3772
  }
2937
- async function getGeminiSession(id, opts = {}) {
2938
- const root = opts.root ?? DEFAULT_GEMINI_ROOT;
2939
- const files = await listSessionFiles(root);
3773
+ async function getAntigravitySession(id, opts = {}) {
3774
+ const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
3775
+ const files = await listSessionFiles2(root);
2940
3776
  let chosen;
2941
3777
  for (const file of files) {
2942
- if (file.filenameId === id || id.startsWith(file.filenameId)) {
3778
+ if (file.conversationId === id) {
2943
3779
  chosen = file;
2944
3780
  break;
2945
3781
  }
2946
3782
  }
2947
- if (!chosen) {
2948
- for (const file of files) {
2949
- const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
2950
- if (meta2.id === id) {
2951
- chosen = file;
2952
- break;
2953
- }
2954
- }
2955
- }
2956
3783
  if (!chosen)
2957
3784
  return null;
2958
- const cached = detailCache3.get(chosen.filePath);
2959
- if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
3785
+ const cached = detailCache4.get(chosen.filePath);
3786
+ if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes && cached.cwd === chosen.cwd) {
2960
3787
  return cached.detail;
2961
3788
  }
2962
- const { meta, events } = await parseSession(chosen);
3789
+ const { meta, events } = await parseSession2(chosen);
2963
3790
  const detail = { ...meta, events };
2964
- detailCache3.set(chosen.filePath, {
3791
+ detailCache4.set(chosen.filePath, {
2965
3792
  detail,
2966
3793
  mtimeMs: chosen.mtimeMs,
2967
- sizeBytes: chosen.sizeBytes
3794
+ sizeBytes: chosen.sizeBytes,
3795
+ cwd: chosen.cwd
2968
3796
  });
2969
3797
  return detail;
2970
3798
  }
2971
- function geminiSessionLocalDay(meta) {
3799
+ function antigravitySessionLocalDay(meta) {
2972
3800
  if (!meta.firstTimestamp)
2973
3801
  return void 0;
2974
3802
  const ms = Date.parse(meta.firstTimestamp);
2975
3803
  return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
2976
3804
  }
2977
- var DEFAULT_GEMINI_ROOT, GEMINI_PROJECTS_FILE, SESSION_FILE_RE, IDLE_GAP_MS2, projectsCache, metaCache3, detailCache3;
2978
- var init_gemini = __esm({
2979
- "../parser/dist/gemini.js"() {
3805
+ var DEFAULT_ANTIGRAVITY_ROOT, IDLE_GAP_MS3, historyCache, metaCache4, detailCache4;
3806
+ var init_antigravity = __esm({
3807
+ "../parser/dist/antigravity.js"() {
2980
3808
  "use strict";
2981
3809
  init_analytics();
2982
3810
  init_user_input();
2983
- DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
2984
- GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
2985
- SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
2986
- IDLE_GAP_MS2 = 3 * 60 * 1e3;
2987
- projectsCache = null;
2988
- metaCache3 = /* @__PURE__ */ new Map();
2989
- detailCache3 = /* @__PURE__ */ new Map();
3811
+ DEFAULT_ANTIGRAVITY_ROOT = path4.join(os4.homedir(), ".gemini", "antigravity-cli");
3812
+ IDLE_GAP_MS3 = 3 * 60 * 1e3;
3813
+ historyCache = null;
3814
+ metaCache4 = /* @__PURE__ */ new Map();
3815
+ detailCache4 = /* @__PURE__ */ new Map();
3816
+ }
3817
+ });
3818
+
3819
+ // ../parser/dist/cowork.js
3820
+ import { promises as fs5 } from "node:fs";
3821
+ import os5 from "node:os";
3822
+ import path5 from "node:path";
3823
+ function defaultCoworkRoot() {
3824
+ const home = os5.homedir();
3825
+ if (process.platform === "darwin") {
3826
+ return path5.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions");
3827
+ }
3828
+ if (process.platform === "win32") {
3829
+ const appData = process.env.APPDATA ?? path5.join(home, "AppData", "Roaming");
3830
+ return path5.join(appData, "Claude", "local-agent-mode-sessions");
3831
+ }
3832
+ return path5.join(home, ".config", "Claude", "local-agent-mode-sessions");
3833
+ }
3834
+ async function safeReaddir4(p) {
3835
+ return fs5.readdir(p).catch(() => []);
3836
+ }
3837
+ async function statMs(p) {
3838
+ const s = await fs5.stat(p).catch(() => null);
3839
+ return s ? s.mtimeMs : 0;
3840
+ }
3841
+ async function listSessionFiles3(root) {
3842
+ const out = [];
3843
+ const accounts = await safeReaddir4(root);
3844
+ for (const accountId of accounts) {
3845
+ const accountDir = path5.join(root, accountId);
3846
+ const workspaces = await safeReaddir4(accountDir);
3847
+ for (const workspaceId of workspaces) {
3848
+ const workspaceDir = path5.join(accountDir, workspaceId);
3849
+ const spacesMtimeMs = await statMs(path5.join(workspaceDir, "spaces.json"));
3850
+ const entries2 = await safeReaddir4(workspaceDir);
3851
+ for (const entry of entries2) {
3852
+ if (!SESSION_ID_RE.test(entry))
3853
+ continue;
3854
+ const auditPath = path5.join(workspaceDir, entry, "audit.jsonl");
3855
+ const auditStat = await fs5.stat(auditPath).catch(() => null);
3856
+ if (!auditStat || !auditStat.isFile() || auditStat.size === 0)
3857
+ continue;
3858
+ const metaPath = path5.join(workspaceDir, `${entry}.json`);
3859
+ const metaMtimeMs = await statMs(metaPath);
3860
+ out.push({
3861
+ sessionId: entry,
3862
+ auditPath,
3863
+ metaPath,
3864
+ workspaceDir,
3865
+ auditMtimeMs: auditStat.mtimeMs,
3866
+ auditSize: auditStat.size,
3867
+ metaMtimeMs,
3868
+ spacesMtimeMs
3869
+ });
3870
+ }
3871
+ }
3872
+ }
3873
+ return out;
3874
+ }
3875
+ async function loadSpacesForWorkspace(workspaceDir) {
3876
+ const spacesPath = path5.join(workspaceDir, "spaces.json");
3877
+ const stat = await fs5.stat(spacesPath).catch(() => null);
3878
+ if (!stat)
3879
+ return /* @__PURE__ */ new Map();
3880
+ const cached = spacesCache.get(workspaceDir);
3881
+ if (cached && cached.mtimeMs === stat.mtimeMs)
3882
+ return cached.spaceIdToPath;
3883
+ const raw = await fs5.readFile(spacesPath, "utf8").catch(() => "");
3884
+ const out = /* @__PURE__ */ new Map();
3885
+ try {
3886
+ const parsed = JSON.parse(raw);
3887
+ for (const space of parsed.spaces ?? []) {
3888
+ const id = typeof space.id === "string" ? space.id : void 0;
3889
+ const folders = Array.isArray(space.folders) ? space.folders : [];
3890
+ const first = folders[0];
3891
+ const folderPath = typeof first?.path === "string" ? first.path : void 0;
3892
+ if (id && folderPath)
3893
+ out.set(id, folderPath);
3894
+ }
3895
+ } catch {
3896
+ }
3897
+ spacesCache.set(workspaceDir, { mtimeMs: stat.mtimeMs, spaceIdToPath: out });
3898
+ return out;
3899
+ }
3900
+ async function readCoworkMeta(metaPath) {
3901
+ const raw = await fs5.readFile(metaPath, "utf8").catch(() => "");
3902
+ if (!raw)
3903
+ return {};
3904
+ try {
3905
+ const j = JSON.parse(raw);
3906
+ return {
3907
+ spaceId: typeof j.spaceId === "string" ? j.spaceId : void 0,
3908
+ userSelectedFolders: Array.isArray(j.userSelectedFolders) ? j.userSelectedFolders.filter((s) => typeof s === "string") : void 0,
3909
+ cwd: typeof j.cwd === "string" ? j.cwd : void 0,
3910
+ model: typeof j.model === "string" ? j.model : void 0,
3911
+ title: typeof j.title === "string" ? j.title : void 0,
3912
+ createdAt: typeof j.createdAt === "number" ? j.createdAt : void 0,
3913
+ lastActivityAt: typeof j.lastActivityAt === "number" ? j.lastActivityAt : void 0
3914
+ };
3915
+ } catch {
3916
+ return {};
3917
+ }
3918
+ }
3919
+ function resolveProject(meta, spaceIdToPath) {
3920
+ let projectPath;
3921
+ if (meta.spaceId)
3922
+ projectPath = spaceIdToPath.get(meta.spaceId);
3923
+ if (!projectPath && meta.userSelectedFolders && meta.userSelectedFolders.length > 0) {
3924
+ projectPath = meta.userSelectedFolders[0];
3925
+ }
3926
+ if (!projectPath) {
3927
+ return { projectName: "cowork:unspaced", projectDir: "cowork-unspaced" };
3928
+ }
3929
+ return {
3930
+ projectName: canonicalProjectName(projectPath),
3931
+ projectDir: projectPath.replace(/^\//, "-").replace(/\//g, "-"),
3932
+ cwd: projectPath
3933
+ };
3934
+ }
3935
+ async function readJsonl2(filePath) {
3936
+ const raw = await fs5.readFile(filePath, "utf8");
3937
+ const out = [];
3938
+ for (const line of raw.split("\n")) {
3939
+ const trimmed = line.trim();
3940
+ if (!trimmed)
3941
+ continue;
3942
+ try {
3943
+ out.push(JSON.parse(trimmed));
3944
+ } catch {
3945
+ }
3946
+ }
3947
+ return out;
3948
+ }
3949
+ async function parseCoworkSession(file) {
3950
+ const [lines, coworkMeta, spaceIdToPath] = await Promise.all([
3951
+ readJsonl2(file.auditPath),
3952
+ readCoworkMeta(file.metaPath),
3953
+ loadSpacesForWorkspace(file.workspaceDir)
3954
+ ]);
3955
+ const { meta: baseMeta, events } = parseTranscript(lines);
3956
+ const { projectName, projectDir, cwd } = resolveProject(coworkMeta, spaceIdToPath);
3957
+ const meta = {
3958
+ ...baseMeta,
3959
+ agent: "cowork",
3960
+ id: file.sessionId,
3961
+ sessionId: file.sessionId,
3962
+ filePath: file.auditPath,
3963
+ projectName,
3964
+ projectDir,
3965
+ cwd: cwd ?? baseMeta.cwd,
3966
+ model: baseMeta.model ?? coworkMeta.model
3967
+ };
3968
+ return { meta, events };
3969
+ }
3970
+ function cacheKeyFor(file) {
3971
+ return {
3972
+ auditMtimeMs: file.auditMtimeMs,
3973
+ auditSize: file.auditSize,
3974
+ metaMtimeMs: file.metaMtimeMs,
3975
+ spacesMtimeMs: file.spacesMtimeMs
3976
+ };
3977
+ }
3978
+ function cacheKeyMatches(a, b) {
3979
+ return a.auditMtimeMs === b.auditMtimeMs && a.auditSize === b.auditSize && a.metaMtimeMs === b.metaMtimeMs && a.spacesMtimeMs === b.spacesMtimeMs;
3980
+ }
3981
+ function clearCoworkCaches() {
3982
+ metaCache5.clear();
3983
+ detailCache5.clear();
3984
+ spacesCache.clear();
3985
+ }
3986
+ async function listCoworkSessions(opts = {}) {
3987
+ const root = opts.root ?? DEFAULT_COWORK_ROOT;
3988
+ const files = await listSessionFiles3(root);
3989
+ const out = [];
3990
+ for (const file of files) {
3991
+ const key = cacheKeyFor(file);
3992
+ const cached = metaCache5.get(file.auditPath);
3993
+ if (cached && cacheKeyMatches(cached.key, key)) {
3994
+ out.push(cached.meta);
3995
+ continue;
3996
+ }
3997
+ try {
3998
+ const { meta } = await parseCoworkSession(file);
3999
+ metaCache5.set(file.auditPath, { meta, key });
4000
+ out.push(meta);
4001
+ } catch {
4002
+ }
4003
+ }
4004
+ out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
4005
+ if (opts.limit !== void 0)
4006
+ return out.slice(0, opts.limit);
4007
+ return out;
4008
+ }
4009
+ async function getCoworkSession(id, opts = {}) {
4010
+ const root = opts.root ?? DEFAULT_COWORK_ROOT;
4011
+ const files = await listSessionFiles3(root);
4012
+ const file = files.find((f) => f.sessionId === id);
4013
+ if (!file)
4014
+ return null;
4015
+ const key = cacheKeyFor(file);
4016
+ const cached = detailCache5.get(file.auditPath);
4017
+ if (cached && cacheKeyMatches(cached.key, key))
4018
+ return cached.detail;
4019
+ const { meta, events } = await parseCoworkSession(file);
4020
+ const detail = { ...meta, events };
4021
+ detailCache5.set(file.auditPath, { detail, key });
4022
+ return detail;
4023
+ }
4024
+ function coworkSessionLocalDay(meta) {
4025
+ if (!meta.firstTimestamp)
4026
+ return void 0;
4027
+ const ms = Date.parse(meta.firstTimestamp);
4028
+ return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
4029
+ }
4030
+ var DEFAULT_COWORK_ROOT, SESSION_ID_RE, spacesCache, metaCache5, detailCache5;
4031
+ var init_cowork = __esm({
4032
+ "../parser/dist/cowork.js"() {
4033
+ "use strict";
4034
+ init_analytics();
4035
+ init_parser();
4036
+ DEFAULT_COWORK_ROOT = defaultCoworkRoot();
4037
+ SESSION_ID_RE = /^local_[0-9a-f-]+$/;
4038
+ spacesCache = /* @__PURE__ */ new Map();
4039
+ metaCache5 = /* @__PURE__ */ new Map();
4040
+ detailCache5 = /* @__PURE__ */ new Map();
2990
4041
  }
2991
4042
  });
2992
4043
 
@@ -3034,11 +4085,14 @@ var init_team_wire = __esm({
3034
4085
  // ../parser/dist/fs.js
3035
4086
  var fs_exports = {};
3036
4087
  __export(fs_exports, {
4088
+ DEFAULT_ANTIGRAVITY_ROOT: () => DEFAULT_ANTIGRAVITY_ROOT,
3037
4089
  DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
4090
+ DEFAULT_COWORK_ROOT: () => DEFAULT_COWORK_ROOT,
3038
4091
  DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
3039
4092
  DEFAULT_ROOT: () => DEFAULT_ROOT,
3040
4093
  RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
3041
4094
  agentSources: () => agentSources,
4095
+ antigravitySessionLocalDay: () => antigravitySessionLocalDay,
3042
4096
  buildCalibrationCurve: () => buildCalibrationCurve,
3043
4097
  cacheStats: () => cacheStats,
3044
4098
  cclensHome: () => cclensHome,
@@ -3046,19 +4100,24 @@ __export(fs_exports, {
3046
4100
  clearCaches: () => clearCaches,
3047
4101
  clearTeamConfig: () => clearTeamConfig,
3048
4102
  codexSessionLocalDay: () => codexSessionLocalDay,
4103
+ coworkSessionLocalDay: () => coworkSessionLocalDay,
3049
4104
  decodeProjectName: () => decodeProjectName,
3050
4105
  findTeamLead: () => findTeamLead,
3051
4106
  geminiSessionLocalDay: () => geminiSessionLocalDay,
3052
4107
  getAgentSource: () => getAgentSource,
4108
+ getAntigravitySession: () => getAntigravitySession,
3053
4109
  getAnySession: () => getAnySession,
3054
4110
  getCodexSession: () => getCodexSession,
4111
+ getCoworkSession: () => getCoworkSession,
3055
4112
  getGeminiSession: () => getGeminiSession,
3056
4113
  getLatestCodexUsage: () => getLatestCodexUsage,
3057
4114
  getSession: () => getSession,
3058
4115
  invalidateFile: () => invalidateFile,
3059
4116
  isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
3060
4117
  listAllSessions: () => listAllSessions,
4118
+ listAntigravitySessions: () => listAntigravitySessions,
3061
4119
  listCodexSessions: () => listCodexSessions,
4120
+ listCoworkSessions: () => listCoworkSessions,
3062
4121
  listGeminiSessions: () => listGeminiSessions,
3063
4122
  listProjects: () => listProjects,
3064
4123
  listSessions: () => listSessions,
@@ -3067,20 +4126,21 @@ __export(fs_exports, {
3067
4126
  loadCalibrationSnapshots: () => loadCalibrationSnapshots,
3068
4127
  loadTeamForSession: () => loadTeamForSession,
3069
4128
  loadUsageByDay: () => loadUsageByDay,
4129
+ loadWorkflowAgentDetail: () => loadWorkflowAgentDetail,
3070
4130
  readJsonlFile: () => readJsonlFile,
3071
4131
  readTeamConfig: () => readTeamConfig,
3072
4132
  sessionIdFromFileName: () => sessionIdFromFileName,
3073
4133
  walkJsonlFiles: () => walkJsonlFiles,
3074
4134
  writeTeamConfig: () => writeTeamConfig
3075
4135
  });
3076
- import { promises as fs4 } from "node:fs";
3077
- import os4 from "node:os";
3078
- import path4 from "node:path";
4136
+ import { promises as fs6 } from "node:fs";
4137
+ import os6 from "node:os";
4138
+ import path6 from "node:path";
3079
4139
  function cclensHome() {
3080
- return process.env.CCLENS_HOME || path4.join(os4.homedir(), ".cclens");
4140
+ return process.env.CCLENS_HOME || path6.join(os6.homedir(), ".cclens");
3081
4141
  }
3082
4142
  function cclensPath(...parts) {
3083
- return path4.join(cclensHome(), ...parts);
4143
+ return path6.join(cclensHome(), ...parts);
3084
4144
  }
3085
4145
  function cacheStats() {
3086
4146
  return claudeCodeCacheStats();
@@ -3089,6 +4149,8 @@ function clearCaches() {
3089
4149
  clearClaudeCodeCaches();
3090
4150
  clearCodexCaches();
3091
4151
  clearGeminiCaches();
4152
+ clearAntigravityCaches();
4153
+ clearCoworkCaches();
3092
4154
  }
3093
4155
  function invalidateFile(fullPath) {
3094
4156
  invalidateClaudeCodeFile(fullPath);
@@ -3120,7 +4182,7 @@ function usageLogPath() {
3120
4182
  async function loadUsageByDay(start2, end) {
3121
4183
  let raw;
3122
4184
  try {
3123
- raw = await fs4.readFile(usageLogPath(), "utf8");
4185
+ raw = await fs6.readFile(usageLogPath(), "utf8");
3124
4186
  } catch {
3125
4187
  return { by_day: [] };
3126
4188
  }
@@ -3165,7 +4227,7 @@ async function loadUsageByDay(start2, end) {
3165
4227
  async function loadCalibrationSnapshots() {
3166
4228
  let raw;
3167
4229
  try {
3168
- raw = await fs4.readFile(usageLogPath(), "utf8");
4230
+ raw = await fs6.readFile(usageLogPath(), "utf8");
3169
4231
  } catch {
3170
4232
  return [];
3171
4233
  }
@@ -3323,7 +4385,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
3323
4385
  ]);
3324
4386
  return buildCalibrationCurve(events, snapshots, tier, granularityMin);
3325
4387
  }
3326
- var codexSource, geminiSource, agentSources;
4388
+ var codexSource, geminiSource, antigravitySource, coworkSource, agentSources;
3327
4389
  var init_fs = __esm({
3328
4390
  "../parser/dist/fs.js"() {
3329
4391
  "use strict";
@@ -3333,9 +4395,13 @@ var init_fs = __esm({
3333
4395
  init_claude_code();
3334
4396
  init_codex();
3335
4397
  init_gemini();
4398
+ init_antigravity();
4399
+ init_cowork();
3336
4400
  init_claude_code();
3337
4401
  init_codex();
3338
4402
  init_gemini();
4403
+ init_antigravity();
4404
+ init_cowork();
3339
4405
  init_team_config();
3340
4406
  init_team_wire();
3341
4407
  codexSource = {
@@ -3369,7 +4435,33 @@ var init_fs = __esm({
3369
4435
  return getGeminiSession(id);
3370
4436
  }
3371
4437
  };
3372
- agentSources = [claudeCodeSource, codexSource, geminiSource];
4438
+ antigravitySource = {
4439
+ ...ANTIGRAVITY_METADATA,
4440
+ defaultRoot: DEFAULT_ANTIGRAVITY_ROOT,
4441
+ async listSessions(opts) {
4442
+ return listAntigravitySessions(opts);
4443
+ },
4444
+ async getSession(id) {
4445
+ return getAntigravitySession(id);
4446
+ }
4447
+ };
4448
+ coworkSource = {
4449
+ ...COWORK_METADATA,
4450
+ defaultRoot: DEFAULT_COWORK_ROOT,
4451
+ async listSessions(opts) {
4452
+ return listCoworkSessions(opts);
4453
+ },
4454
+ async getSession(id) {
4455
+ return getCoworkSession(id);
4456
+ }
4457
+ };
4458
+ agentSources = [
4459
+ claudeCodeSource,
4460
+ codexSource,
4461
+ geminiSource,
4462
+ antigravitySource,
4463
+ coworkSource
4464
+ ];
3373
4465
  }
3374
4466
  });
3375
4467
 
@@ -3442,11 +4534,11 @@ function stopServer() {
3442
4534
  }
3443
4535
  async function checkPort(port) {
3444
4536
  const { createServer } = await import("node:net");
3445
- return new Promise((resolve) => {
4537
+ return new Promise((resolve3) => {
3446
4538
  const server = createServer();
3447
- server.once("error", () => resolve(true));
4539
+ server.once("error", () => resolve3(true));
3448
4540
  server.once("listening", () => {
3449
- server.close(() => resolve(false));
4541
+ server.close(() => resolve3(false));
3450
4542
  });
3451
4543
  server.listen(port, "localhost");
3452
4544
  });
@@ -3776,9 +4868,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
3776
4868
  console.warn(
3777
4869
  ` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
3778
4870
  );
3779
- } else if (verify.installedVersion !== "0.11.2") {
4871
+ } else if (verify.installedVersion !== "0.12.1") {
3780
4872
  console.log(
3781
- ` \u2192 This process is still running ${"0.11.2"}. Next invocation will use ${verify.installedVersion}.`
4873
+ ` \u2192 This process is still running ${"0.12.1"}. Next invocation will use ${verify.installedVersion}.`
3782
4874
  );
3783
4875
  }
3784
4876
  }
@@ -3813,14 +4905,14 @@ async function getUpdateAvailability() {
3813
4905
  if (isDevMode()) return null;
3814
4906
  const latest = await fetchLatestVersion();
3815
4907
  if (latest === null) return {
3816
- current: "0.11.2",
4908
+ current: "0.12.1",
3817
4909
  latest: null,
3818
4910
  updateAvailable: false
3819
4911
  };
3820
4912
  return {
3821
- current: "0.11.2",
4913
+ current: "0.12.1",
3822
4914
  latest,
3823
- updateAvailable: shouldUpdate("0.11.2", latest)
4915
+ updateAvailable: shouldUpdate("0.12.1", latest)
3824
4916
  };
3825
4917
  }
3826
4918
  async function checkForUpdate() {
@@ -3910,7 +5002,7 @@ async function restartServices(state) {
3910
5002
  }
3911
5003
  async function forceUpdate() {
3912
5004
  const latest = await fetchLatestVersion();
3913
- const current = "0.11.2";
5005
+ const current = "0.12.1";
3914
5006
  if (latest === null) {
3915
5007
  console.error("Could not reach npm registry. Check your network.");
3916
5008
  process.exit(1);
@@ -4088,10 +5180,10 @@ async function web(args2) {
4088
5180
  const open = args2.includes("--open");
4089
5181
  const positional = args2.filter((a) => !a.startsWith("--"));
4090
5182
  const rawPath = positional[0] ?? "";
4091
- const path5 = rawPath.startsWith("/") ? rawPath : rawPath ? `/${rawPath}` : "";
5183
+ const path7 = rawPath.startsWith("/") ? rawPath : rawPath ? `/${rawPath}` : "";
4092
5184
  const status2 = getServerStatus();
4093
5185
  if (status2.running) {
4094
- const url = `http://localhost:${status2.port}${path5}`;
5186
+ const url = `http://localhost:${status2.port}${path7}`;
4095
5187
  if (open) {
4096
5188
  console.log(`Opening ${url}`);
4097
5189
  openBrowser(url);
@@ -4103,7 +5195,7 @@ async function web(args2) {
4103
5195
  console.log("fleetlens is not running. Starting server...");
4104
5196
  try {
4105
5197
  const result = await startServer({});
4106
- const url = `http://localhost:${result.port}${path5}`;
5198
+ const url = `http://localhost:${result.port}${path7}`;
4107
5199
  console.log(`fleetlens running on ${url} (PID ${result.pid})`);
4108
5200
  if (open) {
4109
5201
  openBrowser(url);
@@ -4165,9 +5257,9 @@ function readFromCredentialsFile() {
4165
5257
  join5(homedir2(), ".claude", ".credentials.json"),
4166
5258
  join5(homedir2(), ".config", "claude", "credentials.json")
4167
5259
  ];
4168
- for (const path5 of candidates) {
5260
+ for (const path7 of candidates) {
4169
5261
  try {
4170
- const blob = readFileSync6(path5, "utf8");
5262
+ const blob = readFileSync6(path7, "utf8");
4171
5263
  const creds = extractCredentials(blob);
4172
5264
  if (creds) return creds;
4173
5265
  } catch {
@@ -5100,8 +6192,10 @@ var init_aggregate = __esm({
5100
6192
  // ../parser/dist/index.js
5101
6193
  var dist_exports = {};
5102
6194
  __export(dist_exports, {
6195
+ ANTIGRAVITY_METADATA: () => ANTIGRAVITY_METADATA,
5103
6196
  CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
5104
6197
  CODEX_METADATA: () => CODEX_METADATA,
6198
+ COWORK_METADATA: () => COWORK_METADATA,
5105
6199
  GEMINI_METADATA: () => GEMINI_METADATA,
5106
6200
  PRICES: () => PRICES,
5107
6201
  RATE_PER_PCT: () => RATE_PER_PCT,
@@ -5142,6 +6236,7 @@ __export(dist_exports, {
5142
6236
  predictUtilization: () => predictUtilization,
5143
6237
  priorCalendarMonth: () => priorCalendarMonth,
5144
6238
  priorCalendarWeek: () => priorCalendarWeek,
6239
+ projectRepoName: () => projectRepoName,
5145
6240
  rowPrimaryIndex: () => rowPrimaryIndex,
5146
6241
  sessionAirTimeMs: () => sessionAirTimeMs,
5147
6242
  sessionDay: () => sessionDay,
@@ -5345,7 +6440,7 @@ var init_trivial = __esm({
5345
6440
  });
5346
6441
 
5347
6442
  // ../entries/dist/build.js
5348
- var IDLE_GAP_MS3;
6443
+ var IDLE_GAP_MS4;
5349
6444
  var init_build = __esm({
5350
6445
  "../entries/dist/build.js"() {
5351
6446
  "use strict";
@@ -5353,7 +6448,7 @@ var init_build = __esm({
5353
6448
  init_types();
5354
6449
  init_signals();
5355
6450
  init_trivial();
5356
- IDLE_GAP_MS3 = 3 * 60 * 1e3;
6451
+ IDLE_GAP_MS4 = 3 * 60 * 1e3;
5357
6452
  }
5358
6453
  });
5359
6454
 
@@ -5386,11 +6481,11 @@ function digestsDir() {
5386
6481
  digestsDirCached = envOverride ?? cclensPath("digests");
5387
6482
  return digestsDirCached;
5388
6483
  }
5389
- function __setDigestsDirForTest(path5) {
5390
- digestsDirCached = path5;
5391
- mkdirSync4(join6(path5, "day"), { recursive: true });
5392
- mkdirSync4(join6(path5, "week"), { recursive: true });
5393
- mkdirSync4(join6(path5, "month"), { recursive: true });
6484
+ function __setDigestsDirForTest(path7) {
6485
+ digestsDirCached = path7;
6486
+ mkdirSync4(join6(path7, "day"), { recursive: true });
6487
+ mkdirSync4(join6(path7, "week"), { recursive: true });
6488
+ mkdirSync4(join6(path7, "month"), { recursive: true });
5394
6489
  }
5395
6490
  function dayDigestPath(date) {
5396
6491
  return join6(digestsDir(), "day", `${date}.json`);
@@ -5577,9 +6672,9 @@ function entriesDir() {
5577
6672
  entriesDirCached = envOverride ?? cclensPath("entries");
5578
6673
  return entriesDirCached;
5579
6674
  }
5580
- function __setEntriesDirForTest(path5) {
5581
- entriesDirCached = path5;
5582
- mkdirSync5(path5, { recursive: true });
6675
+ function __setEntriesDirForTest(path7) {
6676
+ entriesDirCached = path7;
6677
+ mkdirSync5(path7, { recursive: true });
5583
6678
  }
5584
6679
  function pathFor(sessionId, localDay) {
5585
6680
  return join7(entriesDir(), `${entryKey(sessionId, localDay)}.json`);
@@ -6115,8 +7210,8 @@ var init_parseUtil = __esm({
6115
7210
  init_errors();
6116
7211
  init_en();
6117
7212
  makeIssue = (params) => {
6118
- const { data, path: path5, errorMaps, issueData } = params;
6119
- const fullPath = [...path5, ...issueData.path || []];
7213
+ const { data, path: path7, errorMaps, issueData } = params;
7214
+ const fullPath = [...path7, ...issueData.path || []];
6120
7215
  const fullIssue = {
6121
7216
  ...issueData,
6122
7217
  path: fullPath
@@ -6424,11 +7519,11 @@ var init_types3 = __esm({
6424
7519
  init_parseUtil();
6425
7520
  init_util();
6426
7521
  ParseInputLazyPath = class {
6427
- constructor(parent, value, path5, key) {
7522
+ constructor(parent, value, path7, key) {
6428
7523
  this._cachedPath = [];
6429
7524
  this.parent = parent;
6430
7525
  this.data = value;
6431
- this._path = path5;
7526
+ this._path = path7;
6432
7527
  this._key = key;
6433
7528
  }
6434
7529
  get path() {
@@ -10086,10 +11181,10 @@ function snapshotAllTranscripts() {
10086
11181
  }
10087
11182
  return out;
10088
11183
  }
10089
- function readJsonlCwd(path5, maxLines = 8) {
11184
+ function readJsonlCwd(path7, maxLines = 8) {
10090
11185
  let raw;
10091
11186
  try {
10092
- raw = readFileSync9(path5, "utf8");
11187
+ raw = readFileSync9(path7, "utf8");
10093
11188
  } catch {
10094
11189
  return void 0;
10095
11190
  }
@@ -10143,10 +11238,10 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
10143
11238
  }
10144
11239
  throw new TmuxRunError(`timeout waiting for claude to create the session transcript (cwd: ${targetCwd})`);
10145
11240
  }
10146
- function parseTranscript2(path5, defaultModel) {
11241
+ function parseTranscript2(path7, defaultModel) {
10147
11242
  let raw;
10148
11243
  try {
10149
- raw = readFileSync9(path5, "utf8");
11244
+ raw = readFileSync9(path7, "utf8");
10150
11245
  } catch {
10151
11246
  return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
10152
11247
  }
@@ -10275,15 +11370,15 @@ function newRunId(kind) {
10275
11370
  function tracePath(runId) {
10276
11371
  return join9(RUNS_DIR, `${runId}.jsonl`);
10277
11372
  }
10278
- function safeAppend(path5, line) {
11373
+ function safeAppend(path7, line) {
10279
11374
  try {
10280
- appendFileSync2(path5, line);
11375
+ appendFileSync2(path7, line);
10281
11376
  } catch {
10282
11377
  }
10283
11378
  }
10284
- function safeWrite(path5, line) {
11379
+ function safeWrite(path7, line) {
10285
11380
  try {
10286
- writeFileSync6(path5, line);
11381
+ writeFileSync6(path7, line);
10287
11382
  } catch {
10288
11383
  }
10289
11384
  }
@@ -10361,7 +11456,7 @@ async function runClaudeSubprocess(args2) {
10361
11456
  return runClaudePrintMode(args2);
10362
11457
  }
10363
11458
  function runClaudePrintMode(args2) {
10364
- return new Promise((resolve, reject) => {
11459
+ return new Promise((resolve3, reject) => {
10365
11460
  ensureRunsDir();
10366
11461
  const kind = detectKindFromSystemPrompt(args2.systemPrompt);
10367
11462
  const runId = newRunId(kind);
@@ -10492,7 +11587,7 @@ ${args2.reminder}` : args2.userPrompt;
10492
11587
  reject(new Error(`claude exited ${code}: ${stderr.trim().slice(0, 300)}`));
10493
11588
  return;
10494
11589
  }
10495
- resolve({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
11590
+ resolve3({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
10496
11591
  });
10497
11592
  proc.on("error", (err) => {
10498
11593
  safeAppend(trace, JSON.stringify({ _meta: { type: "spawn_error", run_id: runId, ts: (/* @__PURE__ */ new Date()).toISOString(), error: err.message } }) + "\n");
@@ -10697,8 +11792,8 @@ function spendPath() {
10697
11792
  spendPathCached = cclensPath("llm-spend.jsonl");
10698
11793
  return spendPathCached;
10699
11794
  }
10700
- function __setSpendPathForTest(path5) {
10701
- spendPathCached = path5;
11795
+ function __setSpendPathForTest(path7) {
11796
+ spendPathCached = path7;
10702
11797
  }
10703
11798
  function appendSpend(record) {
10704
11799
  const p = spendPath();
@@ -10748,8 +11843,8 @@ function lockPath() {
10748
11843
  lockPathCached = cclensPath("llm-interactive.lock");
10749
11844
  return lockPathCached;
10750
11845
  }
10751
- function __setInteractiveLockPathForTest(path5) {
10752
- lockPathCached = path5;
11846
+ function __setInteractiveLockPathForTest(path7) {
11847
+ lockPathCached = path7;
10753
11848
  }
10754
11849
  function touchLock() {
10755
11850
  writeFileSync7(lockPath(), String(process.pid), "utf8");
@@ -10832,10 +11927,10 @@ async function runEnrichmentQueue(settings, opts = {}) {
10832
11927
  if (monthToDateSpend() >= budget)
10833
11928
  return { skipped: "budget_cap_reached" };
10834
11929
  const queue = listEntriesWithStatus(["pending", "error"]).filter((e) => (e.enrichment.retry_count ?? 0) < MAX_RETRY_COUNT);
10835
- const todayLocal = toLocalDay2(now());
11930
+ const todayLocal2 = toLocalDay2(now());
10836
11931
  let enriched = 0, errors = 0, skipped = 0;
10837
11932
  for (const entry of queue) {
10838
- if (entry.local_day === todayLocal) {
11933
+ if (entry.local_day === todayLocal2) {
10839
11934
  skipped++;
10840
11935
  continue;
10841
11936
  }
@@ -10906,8 +12001,8 @@ function settingsPath() {
10906
12001
  settingsPathCached = cclensPath("settings.json");
10907
12002
  return settingsPathCached;
10908
12003
  }
10909
- function __setSettingsPathForTest(path5) {
10910
- settingsPathCached = path5;
12004
+ function __setSettingsPathForTest(path7) {
12005
+ settingsPathCached = path7;
10911
12006
  }
10912
12007
  function toDisk(s) {
10913
12008
  return {
@@ -11144,7 +12239,7 @@ function rollupOutcomeDay(entries2) {
11144
12239
  return "exploratory";
11145
12240
  return "trivial";
11146
12241
  }
11147
- function truncate4(s, max) {
12242
+ function truncate5(s, max) {
11148
12243
  if (s.length <= max)
11149
12244
  return s;
11150
12245
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -11200,7 +12295,7 @@ function computeDaySignals(entries2) {
11200
12295
  type,
11201
12296
  count: v.count,
11202
12297
  sample_description: v.sample_description,
11203
- sample_prompt_preview: truncate4(v.sample_prompt_preview, 200)
12298
+ sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
11204
12299
  }));
11205
12300
  const frameCounts = /* @__PURE__ */ new Map();
11206
12301
  for (const s of signalsList) {
@@ -11219,7 +12314,7 @@ function computeDaySignals(entries2) {
11219
12314
  if ((e.first_user ?? "").length > 0)
11220
12315
  verbosity_distribution[s.verbosity] += 1;
11221
12316
  for (const ref of s.external_refs) {
11222
- external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate4(ref.preview, 200) });
12317
+ external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate5(ref.preview, 200) });
11223
12318
  }
11224
12319
  const ints = e.numbers.interrupts ?? 0;
11225
12320
  interrupts += ints;
@@ -12092,7 +13187,7 @@ function computeInteractionModes(entries2) {
12092
13187
  date: entry.local_day,
12093
13188
  project_display: prettyProject3(entry.project),
12094
13189
  type: sa.type,
12095
- prompt_preview: truncate5(sa.prompt_preview, 200)
13190
+ prompt_preview: truncate6(sa.prompt_preview, 200)
12096
13191
  });
12097
13192
  }
12098
13193
  const skillExamples = [];
@@ -12109,7 +13204,7 @@ function computeInteractionModes(entries2) {
12109
13204
  skillExamples.push({
12110
13205
  date: e.local_day,
12111
13206
  skill,
12112
- first_user_preview: truncate5(e.first_user, 200)
13207
+ first_user_preview: truncate6(e.first_user, 200)
12113
13208
  });
12114
13209
  }
12115
13210
  }
@@ -12126,7 +13221,7 @@ function computeInteractionModes(entries2) {
12126
13221
  project_display: prettyProject3(longestTurnEntry.project),
12127
13222
  active_min: longestTurnEntry.numbers.active_min,
12128
13223
  top_tools: longestTurnEntry.top_tools.slice(0, 5),
12129
- first_user_preview: truncate5(longestTurnEntry.first_user, 200)
13224
+ first_user_preview: truncate6(longestTurnEntry.first_user, 200)
12130
13225
  } : null;
12131
13226
  const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
12132
13227
  const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
@@ -12157,7 +13252,7 @@ function computeInteractionModes(entries2) {
12157
13252
  }
12158
13253
  };
12159
13254
  }
12160
- function truncate5(s, max) {
13255
+ function truncate6(s, max) {
12161
13256
  if (s.length <= max)
12162
13257
  return s;
12163
13258
  return s.slice(0, max - 1).trimEnd() + "\u2026";
@@ -12204,7 +13299,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
12204
13299
  evidence_subagent = {
12205
13300
  type: sa.type,
12206
13301
  description: sa.description,
12207
- prompt_preview: truncate5(sa.prompt_preview, 200)
13302
+ prompt_preview: truncate6(sa.prompt_preview, 200)
12208
13303
  };
12209
13304
  }
12210
13305
  const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
@@ -12215,7 +13310,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
12215
13310
  outcome: dayOutcome.get(dd.key) ?? null,
12216
13311
  helpfulness: dayHelp.get(dd.key) ?? null,
12217
13312
  evidence_subagent,
12218
- evidence_first_user: repEntry?.first_user ? truncate5(repEntry.first_user, 200) : null,
13313
+ evidence_first_user: repEntry?.first_user ? truncate6(repEntry.first_user, 200) : null,
12219
13314
  day_signature: dd.day_signature ?? null
12220
13315
  };
12221
13316
  });
@@ -12290,7 +13385,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
12290
13385
  date: day2,
12291
13386
  session_id: ref.session_id,
12292
13387
  ref_kind: ref.kind,
12293
- preview: truncate5(ref.preview, 200)
13388
+ preview: truncate6(ref.preview, 200)
12294
13389
  });
12295
13390
  }
12296
13391
  total_interrupts += signals.comm_style.steering.interrupts;
@@ -12362,7 +13457,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
12362
13457
  count: v.count,
12363
13458
  days: [...v.days].sort(),
12364
13459
  sample_description: v.sample_description,
12365
- sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
13460
+ sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
12366
13461
  })),
12367
13462
  threads,
12368
13463
  communication_style: {
@@ -13010,7 +14105,7 @@ function activeMs(timestamps) {
13010
14105
  let active = 0;
13011
14106
  for (let i = 1; i < ts.length; i++) {
13012
14107
  const dt = ts[i] - ts[i - 1];
13013
- if (dt < IDLE_GAP_MS4)
14108
+ if (dt < IDLE_GAP_MS5)
13014
14109
  active += dt;
13015
14110
  }
13016
14111
  return active;
@@ -13181,7 +14276,7 @@ function buildSessionSlice(entry, events, daySignature) {
13181
14276
  let intEnd = sortedTs[0];
13182
14277
  for (let i = 1; i < sortedTs.length; i++) {
13183
14278
  const dt = sortedTs[i] - intEnd;
13184
- if (dt >= IDLE_GAP_MS4) {
14279
+ if (dt >= IDLE_GAP_MS5) {
13185
14280
  intervals.push({
13186
14281
  start_min: fmtMin(intStart - sliceStartMs),
13187
14282
  end_min: fmtMin(intEnd - sliceStartMs)
@@ -13578,14 +14673,14 @@ async function generateTopSession(slice, opts = {}) {
13578
14673
  void lastModel;
13579
14674
  }
13580
14675
  }
13581
- var IDLE_GAP_MS4, LONG_AUTONOMOUS_MIN, N_USER, N_FIRST_AGENT, N_LAST_AGENT, N_USER_TURN1, N_SUBAGENT, SHELL_NOISE, INTERRUPT_RE2, PR_TITLE_RE, PinResponseSchema, TopSessionResponseSchema, SYSTEM_PROMPT5, TOP_SESSION_SYSTEM_PROMPT, DEFAULT_MODEL5, defaultCallLLMTopSession, validateTopSession;
14676
+ var IDLE_GAP_MS5, LONG_AUTONOMOUS_MIN, N_USER, N_FIRST_AGENT, N_LAST_AGENT, N_USER_TURN1, N_SUBAGENT, SHELL_NOISE, INTERRUPT_RE2, PR_TITLE_RE, PinResponseSchema, TopSessionResponseSchema, SYSTEM_PROMPT5, TOP_SESSION_SYSTEM_PROMPT, DEFAULT_MODEL5, defaultCallLLMTopSession, validateTopSession;
13582
14677
  var init_top_sessions = __esm({
13583
14678
  "../entries/dist/top-sessions.js"() {
13584
14679
  "use strict";
13585
14680
  init_zod();
13586
14681
  init_signals();
13587
14682
  init_llm_runner();
13588
- IDLE_GAP_MS4 = 3 * 60 * 1e3;
14683
+ IDLE_GAP_MS5 = 3 * 60 * 1e3;
13589
14684
  LONG_AUTONOMOUS_MIN = 20;
13590
14685
  N_USER = 150;
13591
14686
  N_FIRST_AGENT = 150;
@@ -14104,6 +15199,10 @@ async function* runMonthDigestPipeline(yearMonth, opts) {
14104
15199
  } else {
14105
15200
  digest2.is_live = true;
14106
15201
  setCurrentMonthDigestInCache(yearMonth, digest2, now());
15202
+ if (opts.force === true) {
15203
+ writeMonthDigest(digest2);
15204
+ yield { type: "saved", path: `~/.cclens/digests/month/${yearMonth}.json` };
15205
+ }
14107
15206
  }
14108
15207
  yield { type: "digest", digest: digest2 };
14109
15208
  } finally {
@@ -14719,16 +15818,12 @@ function bucketToRollup(b) {
14719
15818
  };
14720
15819
  }
14721
15820
  function buildRollupsForRange(sessions, sinceDay) {
14722
- const buckets = dailyActivity(sessions);
14723
15821
  const startCounts = /* @__PURE__ */ new Map();
14724
15822
  for (const s of sessions) {
14725
15823
  const d = sessionDay(s);
14726
15824
  if (d) startCounts.set(d, (startCounts.get(d) ?? 0) + 1);
14727
15825
  }
14728
- return buckets.filter((b) => !sinceDay || b.date >= sinceDay).map((b) => ({
14729
- ...bucketToRollup(b),
14730
- sessions: startCounts.get(b.date) ?? 0
14731
- }));
15826
+ return dailyActivity(sessions).filter((b) => !sinceDay || b.date >= sinceDay).map((b) => ({ ...bucketToRollup(b), uniqueSessions: startCounts.get(b.date) ?? 0 }));
14732
15827
  }
14733
15828
  function dayBoundsMs(day2) {
14734
15829
  const [y, m, d] = day2.split("-").map(Number);
@@ -14754,7 +15849,7 @@ function sessionTouchesDay(s, day2) {
14754
15849
  }
14755
15850
  return sessionDay(s) === day2;
14756
15851
  }
14757
- function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects) {
15852
+ function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects, resolveRepo) {
14758
15853
  const bounds = dayBoundsMs(day2);
14759
15854
  const clippedSessions = [];
14760
15855
  for (const s of daySessions) {
@@ -14764,16 +15859,40 @@ function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects) {
14764
15859
  }
14765
15860
  const bursts = computeBurstsFromSessions(clippedSessions);
14766
15861
  const stats = summarizeBursts(bursts);
15862
+ const repoForEntry = (e) => {
15863
+ if (resolveRepo) {
15864
+ const own = resolveRepo(e.project);
15865
+ if (own) return own;
15866
+ const counts = /* @__PURE__ */ new Map();
15867
+ for (const d of e.edited_dirs ?? []) {
15868
+ const r = resolveRepo(d);
15869
+ if (r) counts.set(r, (counts.get(r) ?? 0) + 1);
15870
+ }
15871
+ const dominant = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];
15872
+ if (dominant) return dominant;
15873
+ }
15874
+ return e.github_repos?.length === 1 ? e.github_repos[0] : null;
15875
+ };
15876
+ const sessionRepo = /* @__PURE__ */ new Map();
15877
+ for (const e of entries2) {
15878
+ if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
15879
+ const r = repoForEntry(e);
15880
+ if (r) sessionRepo.set(e.session_id, r);
15881
+ }
14767
15882
  const projects = /* @__PURE__ */ new Map();
14768
15883
  for (const s of clippedSessions) {
14769
- const name = canonicalProjectName(s.projectName);
14770
- if (privateProjects.has(name)) continue;
15884
+ const canonical = canonicalProjectName(s.projectName);
15885
+ const name = projectRepoName(s.projectName);
15886
+ if (privateProjects.has(name) || privateProjects.has(canonical)) continue;
15887
+ const repo = resolveRepo?.(canonical) ?? sessionRepo.get(s.id);
15888
+ const key = repo ?? name;
14771
15889
  const ms = s.activeSegments.reduce((sum, seg) => sum + (seg.endMs - seg.startMs), 0);
14772
- const cur = projects.get(name) ?? { agentTimeMs: 0, sessions: 0 };
15890
+ const cur = projects.get(key) ?? { project: name, agentTimeMs: 0, sessions: 0, ...repo ? { resolved: repo } : {} };
14773
15891
  cur.agentTimeMs += ms;
14774
15892
  cur.sessions += 1;
14775
- projects.set(name, cur);
15893
+ projects.set(key, cur);
14776
15894
  }
15895
+ const projectRepos = /* @__PURE__ */ new Map();
14777
15896
  const workingShapes = /* @__PURE__ */ new Map();
14778
15897
  const skills = /* @__PURE__ */ new Map();
14779
15898
  const subagents = /* @__PURE__ */ new Map();
@@ -14787,12 +15906,12 @@ function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects) {
14787
15906
  let longTotalMin = 0;
14788
15907
  let longMaxSingleMin = 0;
14789
15908
  for (const e of entries2) {
14790
- if (privateProjects.has(e.project)) continue;
15909
+ if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
14791
15910
  const shape = e.signals?.working_shape ?? null;
14792
15911
  if (shape) {
14793
15912
  const cur = workingShapes.get(shape) ?? { sessions: 0, agentTimeMs: 0 };
14794
15913
  cur.sessions += 1;
14795
- cur.agentTimeMs += e.numbers.active_min * 6e4;
15914
+ cur.agentTimeMs += Math.round(e.numbers.active_min * 6e4);
14796
15915
  workingShapes.set(shape, cur);
14797
15916
  }
14798
15917
  for (const [name, count] of Object.entries(e.skills)) {
@@ -14807,6 +15926,12 @@ function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects) {
14807
15926
  prs += e.numbers.prs;
14808
15927
  commits += e.numbers.commits;
14809
15928
  pushes += e.numbers.pushes;
15929
+ if (e.github_repos?.length) {
15930
+ const key = sessionRepo.get(e.session_id) ?? projectRepoName(e.project);
15931
+ const set = projectRepos.get(key) ?? /* @__PURE__ */ new Set();
15932
+ for (const r of e.github_repos) set.add(r);
15933
+ projectRepos.set(key, set);
15934
+ }
14810
15935
  if (e.flags.includes("long_autonomous")) {
14811
15936
  longCount += 1;
14812
15937
  longTotalMin += e.numbers.active_min;
@@ -14814,11 +15939,21 @@ function buildRichRollupBlocks(day2, daySessions, entries2, privateProjects) {
14814
15939
  }
14815
15940
  }
14816
15941
  return {
14817
- projects: Array.from(projects.entries()).map(([project, v]) => ({ project, ...v })).sort((a, b) => b.agentTimeMs - a.agentTimeMs),
15942
+ projects: Array.from(projects.entries()).map(([key, v]) => {
15943
+ const extras = [...projectRepos.get(key) ?? []].filter((r) => r !== v.resolved);
15944
+ const repos = v.resolved ? [v.resolved, ...extras] : extras;
15945
+ return {
15946
+ project: v.project,
15947
+ agentTimeMs: v.agentTimeMs,
15948
+ sessions: v.sessions,
15949
+ ...repos.length ? { githubRepos: repos.slice(0, 5) } : {}
15950
+ };
15951
+ }).sort((a, b) => b.agentTimeMs - a.agentTimeMs),
14818
15952
  workingShapes: Array.from(workingShapes.entries()).map(([shape, v]) => ({ shape, ...v })).sort((a, b) => b.sessions - a.sessions),
14819
15953
  concurrencyPeak: stats.peakConcurrent,
14820
15954
  parallelMinutes: Math.round(stats.totalParallelMs / 6e4),
14821
- longAutonomous: { count: longCount, totalMin: longTotalMin, maxSingleMin: longMaxSingleMin },
15955
+ // Wire schema requires integer minutes (active_min is a float).
15956
+ longAutonomous: { count: longCount, totalMin: Math.round(longTotalMin), maxSingleMin: Math.round(longMaxSingleMin) },
14822
15957
  toolErrors,
14823
15958
  skillsLoaded: Array.from(skills.entries()).map(([name, sessions]) => ({ name, sessions })).sort((a, b) => b.sessions - a.sessions),
14824
15959
  subagentsDispatched: Array.from(subagents.entries()).map(([type, count]) => ({ type, count })).sort((a, b) => b.count - a.count),
@@ -14847,10 +15982,10 @@ function buildEnrichedExtras(entries2) {
14847
15982
  }
14848
15983
  return { outcomeMix, helpfulnessMix, goalMix };
14849
15984
  }
14850
- function buildRichBlocksForDay(day2, daySessions, privateProjects, enrichmentOptIn) {
15985
+ function buildRichBlocksForDay(day2, daySessions, privateProjects, enrichmentOptIn, resolveRepo) {
14851
15986
  const entries2 = listEntriesForDay(day2);
14852
15987
  if (entries2.length === 0) return void 0;
14853
- const rich = buildRichRollupBlocks(day2, daySessions, entries2, privateProjects);
15988
+ const rich = buildRichRollupBlocks(day2, daySessions, entries2, privateProjects, resolveRepo);
14854
15989
  const enriched = enrichmentOptIn ? buildEnrichedExtras(entries2) : void 0;
14855
15990
  return enriched ? { rich, enriched } : { rich };
14856
15991
  }
@@ -14859,10 +15994,11 @@ function buildIngestPayload(inputs) {
14859
15994
  return {
14860
15995
  ingestId: randomUUID2(),
14861
15996
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
14862
- ...richRollup || inputs.enrichedExtras ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
15997
+ ...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
14863
15998
  ...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
14864
15999
  ...richRollup ? { richRollup } : {},
14865
16000
  ...inputs.enrichedExtras ? { enrichedExtras: inputs.enrichedExtras } : {},
16001
+ ...inputs.artifactSignals ? { artifactSignals: inputs.artifactSignals } : {},
14866
16002
  ...inputs.usageSnapshot ? { usageSnapshot: inputs.usageSnapshot } : {},
14867
16003
  ...inputs.planTier ? { planTier: inputs.planTier } : {},
14868
16004
  ...inputs.cyclePeaks ? { cyclePeaks: inputs.cyclePeaks } : {}
@@ -14894,15 +16030,83 @@ var init_push = __esm({
14894
16030
  }
14895
16031
  });
14896
16032
 
16033
+ // src/team/git-remote.ts
16034
+ import { existsSync as existsSync12, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
16035
+ import { dirname as dirname9, isAbsolute, join as join10, resolve } from "node:path";
16036
+ function parseGithubRemote(url) {
16037
+ const m = url.trim().match(GITHUB_URL_RE);
16038
+ return m ? `${m[1]}/${m[2]}`.toLowerCase() : null;
16039
+ }
16040
+ function originUrl(configText) {
16041
+ let inOrigin = false;
16042
+ for (const line of configText.split("\n")) {
16043
+ const t = line.trim();
16044
+ if (t.startsWith("[")) {
16045
+ inOrigin = /^\[remote\s+"origin"\]/.test(t);
16046
+ continue;
16047
+ }
16048
+ if (!inOrigin) continue;
16049
+ const m = t.match(/^url\s*=\s*(.+)$/);
16050
+ if (m) return m[1].trim();
16051
+ }
16052
+ return null;
16053
+ }
16054
+ function gitConfigPathFor(dir) {
16055
+ const dotGit = join10(dir, ".git");
16056
+ const st = statSync3(dotGit, { throwIfNoEntry: false });
16057
+ if (!st) return null;
16058
+ if (st.isDirectory()) return join10(dotGit, "config");
16059
+ const m = readFileSync13(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
16060
+ if (!m) return null;
16061
+ const gd = isAbsolute(m[1]) ? m[1] : resolve(dir, m[1]);
16062
+ const commondirFile = join10(gd, "commondir");
16063
+ if (existsSync12(commondirFile)) {
16064
+ const common = readFileSync13(commondirFile, "utf8").trim();
16065
+ return join10(isAbsolute(common) ? common : resolve(gd, common), "config");
16066
+ }
16067
+ return join10(gd, "config");
16068
+ }
16069
+ function createRepoResolver() {
16070
+ const cache = /* @__PURE__ */ new Map();
16071
+ return (dir) => {
16072
+ if (!dir || !isAbsolute(dir)) return null;
16073
+ const hit = cache.get(dir);
16074
+ if (hit !== void 0) return hit;
16075
+ let repo = null;
16076
+ try {
16077
+ for (let d = dir; ; d = dirname9(d)) {
16078
+ const config = gitConfigPathFor(d);
16079
+ if (config && existsSync12(config)) {
16080
+ const url = originUrl(readFileSync13(config, "utf8"));
16081
+ repo = url ? parseGithubRemote(url) : null;
16082
+ break;
16083
+ }
16084
+ if (d === dirname9(d)) break;
16085
+ }
16086
+ } catch {
16087
+ repo = null;
16088
+ }
16089
+ cache.set(dir, repo);
16090
+ return repo;
16091
+ };
16092
+ }
16093
+ var GITHUB_URL_RE;
16094
+ var init_git_remote = __esm({
16095
+ "src/team/git-remote.ts"() {
16096
+ "use strict";
16097
+ GITHUB_URL_RE = /github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/;
16098
+ }
16099
+ });
16100
+
14897
16101
  // src/team/queue.ts
14898
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync4, statSync as statSync3, mkdirSync as mkdirSync10 } from "node:fs";
14899
- import { dirname as dirname9 } from "node:path";
16102
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, appendFileSync as appendFileSync4, statSync as statSync4, mkdirSync as mkdirSync10 } from "node:fs";
16103
+ import { dirname as dirname10 } from "node:path";
14900
16104
  function enqueuePayload(payload, queuePath = QUEUE_PATH) {
14901
- mkdirSync10(dirname9(queuePath), { recursive: true });
16105
+ mkdirSync10(dirname10(queuePath), { recursive: true });
14902
16106
  const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
14903
16107
  appendFileSync4(queuePath, JSON.stringify(entry) + "\n", "utf8");
14904
16108
  try {
14905
- const { size } = statSync3(queuePath);
16109
+ const { size } = statSync4(queuePath);
14906
16110
  if (size > MAX_SIZE_BYTES) {
14907
16111
  pruneOldest(queuePath);
14908
16112
  }
@@ -14912,7 +16116,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
14912
16116
  function dequeuePayloads(queuePath = QUEUE_PATH) {
14913
16117
  let lines;
14914
16118
  try {
14915
- lines = readFileSync13(queuePath, "utf8").trim().split("\n").filter(Boolean);
16119
+ lines = readFileSync14(queuePath, "utf8").trim().split("\n").filter(Boolean);
14916
16120
  } catch {
14917
16121
  return [];
14918
16122
  }
@@ -14933,7 +16137,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
14933
16137
  function pruneOldest(queuePath) {
14934
16138
  let lines;
14935
16139
  try {
14936
- lines = readFileSync13(queuePath, "utf8").trim().split("\n").filter(Boolean);
16140
+ lines = readFileSync14(queuePath, "utf8").trim().split("\n").filter(Boolean);
14937
16141
  } catch {
14938
16142
  return;
14939
16143
  }
@@ -14952,8 +16156,8 @@ var init_queue2 = __esm({
14952
16156
  });
14953
16157
 
14954
16158
  // src/usage/profile.ts
14955
- import { existsSync as existsSync12, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
14956
- import { dirname as dirname10 } from "node:path";
16159
+ import { existsSync as existsSync13, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "node:fs";
16160
+ import { dirname as dirname11 } from "node:path";
14957
16161
  function mapRateLimitTier(rateLimitTier) {
14958
16162
  switch (rateLimitTier) {
14959
16163
  case "default_claude_pro":
@@ -14993,9 +16197,9 @@ async function fetchProfile(nowMs = Date.now()) {
14993
16197
  };
14994
16198
  }
14995
16199
  function readCachedProfile(cachePath) {
14996
- if (!existsSync12(cachePath)) return null;
16200
+ if (!existsSync13(cachePath)) return null;
14997
16201
  try {
14998
- const raw = JSON.parse(readFileSync14(cachePath, "utf8"));
16202
+ const raw = JSON.parse(readFileSync15(cachePath, "utf8"));
14999
16203
  if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
15000
16204
  return raw;
15001
16205
  } catch {
@@ -15003,7 +16207,7 @@ function readCachedProfile(cachePath) {
15003
16207
  }
15004
16208
  }
15005
16209
  function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
15006
- mkdirSync11(dirname10(cachePath), { recursive: true });
16210
+ mkdirSync11(dirname11(cachePath), { recursive: true });
15007
16211
  writeFileSync10(
15008
16212
  cachePath,
15009
16213
  JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
@@ -15185,11 +16389,11 @@ var init_backfill = __esm({
15185
16389
 
15186
16390
  // src/team/last-push.ts
15187
16391
  import { writeFileSync as writeFileSync11, unlinkSync as unlinkSync5, mkdirSync as mkdirSync12 } from "node:fs";
15188
- import { join as join10 } from "node:path";
16392
+ import { join as join11 } from "node:path";
15189
16393
  function write(record, dir) {
15190
16394
  const d = dir ?? cclensHome();
15191
16395
  mkdirSync12(d, { recursive: true });
15192
- writeFileSync11(join10(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
16396
+ writeFileSync11(join11(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
15193
16397
  }
15194
16398
  function writeLastPushSuccess(payload, dir) {
15195
16399
  write({ pushedAt: (/* @__PURE__ */ new Date()).toISOString(), ok: true, payload }, dir);
@@ -15200,7 +16404,7 @@ function writeLastPushFailure(payload, error, dir) {
15200
16404
  function clearLastPush(dir) {
15201
16405
  const d = dir ?? cclensHome();
15202
16406
  try {
15203
- unlinkSync5(join10(d, LAST_PUSH_FILE));
16407
+ unlinkSync5(join11(d, LAST_PUSH_FILE));
15204
16408
  } catch {
15205
16409
  }
15206
16410
  }
@@ -15213,6 +16417,194 @@ var init_last_push = __esm({
15213
16417
  }
15214
16418
  });
15215
16419
 
16420
+ // src/perception/file-probe.ts
16421
+ var file_probe_exports = {};
16422
+ __export(file_probe_exports, {
16423
+ pathHash: () => pathHash,
16424
+ probeArtifactSignals: () => probeArtifactSignals
16425
+ });
16426
+ import { createHash } from "node:crypto";
16427
+ import { existsSync as existsSync14, readdirSync as readdirSync4, statSync as statSync5 } from "node:fs";
16428
+ import { homedir as homedir4 } from "node:os";
16429
+ import { join as join12, relative, resolve as resolve2, sep } from "node:path";
16430
+ import { execFileSync as execFileSync2 } from "node:child_process";
16431
+ function pathHash(relPath) {
16432
+ return createHash("sha256").update(relPath.split(sep).join("/")).digest("hex").slice(0, 32);
16433
+ }
16434
+ function defaultScanRoots(extraRoots = []) {
16435
+ const roots = [];
16436
+ const home = join12(homedir4(), ".claude");
16437
+ if (existsSync14(home)) roots.push({ root: home, label: "user" });
16438
+ for (const e of extraRoots) {
16439
+ const r = resolve2(e, ".claude");
16440
+ if (existsSync14(r) && r !== home) roots.push({ root: r, label: "project" });
16441
+ }
16442
+ return roots;
16443
+ }
16444
+ function listMarkdownFiles(dir) {
16445
+ if (!existsSync14(dir)) return [];
16446
+ const out = [];
16447
+ let entries2;
16448
+ try {
16449
+ entries2 = readdirSync4(dir);
16450
+ } catch {
16451
+ return [];
16452
+ }
16453
+ for (const name of entries2) {
16454
+ if (name.startsWith(".")) continue;
16455
+ const full = join12(dir, name);
16456
+ let stat;
16457
+ try {
16458
+ stat = statSync5(full);
16459
+ } catch {
16460
+ continue;
16461
+ }
16462
+ if (stat.isDirectory()) {
16463
+ out.push(...listMarkdownFiles(full));
16464
+ } else if (stat.isFile() && name.endsWith(".md")) {
16465
+ out.push(full);
16466
+ }
16467
+ }
16468
+ return out;
16469
+ }
16470
+ function firstSeenDateOf(file) {
16471
+ try {
16472
+ const out = execFileSync2(
16473
+ "git",
16474
+ ["log", "--diff-filter=A", "--follow", "--format=%cs", "--", file],
16475
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname12(file) }
16476
+ ).trim().split("\n").filter(Boolean);
16477
+ if (out.length > 0) return out[out.length - 1];
16478
+ } catch {
16479
+ }
16480
+ try {
16481
+ const s = statSync5(file);
16482
+ return new Date((s.birthtime || s.mtime).getTime()).toISOString().slice(0, 10);
16483
+ } catch {
16484
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
16485
+ }
16486
+ }
16487
+ function dirname12(p) {
16488
+ const i = p.lastIndexOf(sep);
16489
+ return i < 0 ? "." : p.slice(0, i);
16490
+ }
16491
+ function detectGitEmail(cwd) {
16492
+ try {
16493
+ return execFileSync2("git", ["config", "user.email"], {
16494
+ encoding: "utf8",
16495
+ stdio: ["ignore", "pipe", "ignore"],
16496
+ cwd
16497
+ }).trim() || null;
16498
+ } catch {
16499
+ return null;
16500
+ }
16501
+ }
16502
+ function todayLocal() {
16503
+ const d = /* @__PURE__ */ new Date();
16504
+ const y = d.getFullYear();
16505
+ const m = String(d.getMonth() + 1).padStart(2, "0");
16506
+ const day2 = String(d.getDate()).padStart(2, "0");
16507
+ return `${y}-${m}-${day2}`;
16508
+ }
16509
+ function scanAuthored(roots, subdir, day2) {
16510
+ const out = [];
16511
+ for (const r of roots) {
16512
+ const dir = join12(r.root, subdir);
16513
+ if (!existsSync14(dir)) continue;
16514
+ for (const f of listMarkdownFiles(dir)) {
16515
+ const firstSeen = firstSeenDateOf(f);
16516
+ if (firstSeen !== day2) continue;
16517
+ const rel = relative(dir, f);
16518
+ out.push({ pathHash: pathHash(`${r.label}:${subdir}:${rel}`), firstSeenDate: firstSeen });
16519
+ }
16520
+ }
16521
+ return out;
16522
+ }
16523
+ function scanEdited(roots, day2) {
16524
+ const out = [];
16525
+ for (const r of roots) {
16526
+ const dir = join12(r.root, "skills");
16527
+ if (!existsSync14(dir)) continue;
16528
+ for (const f of listMarkdownFiles(dir)) {
16529
+ const firstSeen = firstSeenDateOf(f);
16530
+ if (firstSeen === day2) continue;
16531
+ let stat;
16532
+ try {
16533
+ stat = statSync5(f);
16534
+ } catch {
16535
+ continue;
16536
+ }
16537
+ const mtimeDay = new Date(stat.mtime.getTime()).toISOString().slice(0, 10);
16538
+ if (mtimeDay !== day2) continue;
16539
+ const rel = relative(dir, f);
16540
+ out.push({ pathHash: pathHash(`${r.label}:skills:${rel}`), lineDelta: 0 });
16541
+ }
16542
+ }
16543
+ return out;
16544
+ }
16545
+ function claudemdLineDelta(extraRoots, authorEmail, day2) {
16546
+ let delta = 0;
16547
+ const candidates = [];
16548
+ for (const e of extraRoots) {
16549
+ const f = resolve2(e, "CLAUDE.md");
16550
+ if (existsSync14(f)) candidates.push(f);
16551
+ }
16552
+ const homeClaudeMd = join12(homedir4(), "CLAUDE.md");
16553
+ if (existsSync14(homeClaudeMd)) candidates.push(homeClaudeMd);
16554
+ for (const file of candidates) {
16555
+ try {
16556
+ const out = execFileSync2(
16557
+ "git",
16558
+ ["log", "--numstat", "--format=COMMIT %cs %ae", "--", file],
16559
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname12(file) }
16560
+ );
16561
+ let currentDate = "";
16562
+ let currentEmail = "";
16563
+ for (const line of out.split("\n")) {
16564
+ if (line.startsWith("COMMIT ")) {
16565
+ const parts = line.slice("COMMIT ".length).trim().split(/\s+/);
16566
+ currentDate = parts[0] ?? "";
16567
+ currentEmail = parts.slice(1).join(" ");
16568
+ } else if (currentDate === day2 && line.trim().length > 0) {
16569
+ if (authorEmail && currentEmail !== authorEmail) continue;
16570
+ const parts = line.split(/\s+/);
16571
+ const added = Number(parts[0]);
16572
+ const removed = Number(parts[1]);
16573
+ if (Number.isFinite(added) && Number.isFinite(removed)) {
16574
+ delta += added - removed;
16575
+ }
16576
+ }
16577
+ }
16578
+ } catch {
16579
+ }
16580
+ }
16581
+ return delta;
16582
+ }
16583
+ function probeArtifactSignals(opts = {}) {
16584
+ const day2 = opts.day ?? todayLocal();
16585
+ const roots = defaultScanRoots(opts.extraRoots);
16586
+ const skillsAuthored = scanAuthored(roots, "skills", day2);
16587
+ const subagentsAuthored = scanAuthored(roots, "agents", day2);
16588
+ const slashCommandsAuthored = scanAuthored(roots, "commands", day2);
16589
+ const skillsEdited = scanEdited(roots, day2);
16590
+ const authorEmail = opts.authorEmail ?? detectGitEmail(opts.extraRoots?.[0] ?? process.cwd()) ?? void 0;
16591
+ const claudemd = claudemdLineDelta(opts.extraRoots ?? [], authorEmail, day2);
16592
+ const empty = skillsAuthored.length === 0 && subagentsAuthored.length === 0 && slashCommandsAuthored.length === 0 && skillsEdited.length === 0 && claudemd === 0;
16593
+ if (empty) return null;
16594
+ return {
16595
+ skillsAuthored,
16596
+ skillsEdited,
16597
+ subagentsAuthored,
16598
+ slashCommandsAuthored,
16599
+ claudemdLineDelta: claudemd
16600
+ };
16601
+ }
16602
+ var init_file_probe = __esm({
16603
+ "src/perception/file-probe.ts"() {
16604
+ "use strict";
16605
+ }
16606
+ });
16607
+
15216
16608
  // src/team/commands.ts
15217
16609
  async function dispatchCommand(command2, config, log) {
15218
16610
  switch (command2.type) {
@@ -15230,6 +16622,7 @@ async function dispatchCommand(command2, config, log) {
15230
16622
  async function runActivityBackfill(command2, config, log) {
15231
16623
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
15232
16624
  const { toLocalDay: toLocalDay4 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
16625
+ const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
15233
16626
  const days = command2.params.days;
15234
16627
  const todayMs = Date.now();
15235
16628
  const targetDayMs = todayMs - (days - 1) * 24 * 60 * 60 * 1e3;
@@ -15255,9 +16648,24 @@ async function runActivityBackfill(command2, config, log) {
15255
16648
  summary: { pushed: 0, fromDay: targetDay }
15256
16649
  };
15257
16650
  }
16651
+ const privateProjects = new Set(config.privateProjects ?? []);
16652
+ const enrichmentOptIn = !!config.enrichmentOptIn;
16653
+ const resolveRepo = createRepoResolver();
15258
16654
  let pushed = 0;
15259
16655
  for (const rollup of rollups) {
15260
- const payload = buildIngestPayload({ rollup });
16656
+ const daySessions = sessions.filter((s) => sessionTouchesDay(s, rollup.day));
16657
+ const richBlocks = buildRichBlocksForDay(rollup.day, daySessions, privateProjects, enrichmentOptIn, resolveRepo);
16658
+ let artifactSignals = null;
16659
+ try {
16660
+ artifactSignals = probeArtifactSignals2({ day: rollup.day, extraRoots: [process.cwd()] });
16661
+ } catch {
16662
+ }
16663
+ const payload = buildIngestPayload({
16664
+ rollup,
16665
+ richExtras: richBlocks?.rich,
16666
+ enrichedExtras: richBlocks?.enriched,
16667
+ artifactSignals: artifactSignals ?? void 0
16668
+ });
15261
16669
  const result = await pushToTeamServer(config, payload);
15262
16670
  if (!result.ok) {
15263
16671
  return {
@@ -15281,6 +16689,7 @@ var init_commands = __esm({
15281
16689
  "src/team/commands.ts"() {
15282
16690
  "use strict";
15283
16691
  init_push();
16692
+ init_git_remote();
15284
16693
  }
15285
16694
  });
15286
16695
 
@@ -15388,6 +16797,8 @@ async function runTeamSync(log = noopLog2, configOverride, options = {}) {
15388
16797
  let lastPushedDay;
15389
16798
  const privateProjects = new Set(config.privateProjects ?? []);
15390
16799
  const enrichmentOptIn = !!config.enrichmentOptIn;
16800
+ const resolveRepo = createRepoResolver();
16801
+ const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
15391
16802
  for (let i = 0; i < rollups.length; i++) {
15392
16803
  const rollup = rollups[i];
15393
16804
  const isLatest = i === rollups.length - 1;
@@ -15396,12 +16807,22 @@ async function runTeamSync(log = noopLog2, configOverride, options = {}) {
15396
16807
  rollup.day,
15397
16808
  daySessions,
15398
16809
  privateProjects,
15399
- enrichmentOptIn
16810
+ enrichmentOptIn,
16811
+ resolveRepo
15400
16812
  );
16813
+ let artifactSignals = null;
16814
+ try {
16815
+ artifactSignals = probeArtifactSignals2({
16816
+ day: rollup.day,
16817
+ extraRoots: [process.cwd()]
16818
+ });
16819
+ } catch {
16820
+ }
15401
16821
  const payload = buildIngestPayload({
15402
16822
  rollup,
15403
16823
  richExtras: richBlocks?.rich,
15404
16824
  enrichedExtras: richBlocks?.enriched,
16825
+ artifactSignals: artifactSignals ?? void 0,
15405
16826
  usageSnapshot: isLatest ? usageSnapshot : void 0,
15406
16827
  planTier,
15407
16828
  // Same rationale as usageSnapshot — current cycle data only on the
@@ -15522,6 +16943,7 @@ var init_sync = __esm({
15522
16943
  "use strict";
15523
16944
  init_config();
15524
16945
  init_push();
16946
+ init_git_remote();
15525
16947
  init_queue2();
15526
16948
  init_backfill();
15527
16949
  init_last_push();
@@ -15677,11 +17099,11 @@ var logs_exports = {};
15677
17099
  __export(logs_exports, {
15678
17100
  teamLogs: () => teamLogs
15679
17101
  });
15680
- import { readFileSync as readFileSync15 } from "node:fs";
17102
+ import { readFileSync as readFileSync16 } from "node:fs";
15681
17103
  async function teamLogs() {
15682
17104
  const logPath = cclensPath("daemon.log");
15683
17105
  try {
15684
- const lines = readFileSync15(logPath, "utf8").trim().split("\n");
17106
+ const lines = readFileSync16(logPath, "utf8").trim().split("\n");
15685
17107
  const teamLines = lines.filter((l) => l.includes("team "));
15686
17108
  if (teamLines.length === 0) {
15687
17109
  console.log("No team-related log entries found.");
@@ -15787,8 +17209,8 @@ __export(runs_exports, {
15787
17209
  runs: () => runs
15788
17210
  });
15789
17211
  import { execSync as execSync2 } from "node:child_process";
15790
- import { existsSync as existsSync13, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
15791
- import { join as join11 } from "node:path";
17212
+ import { existsSync as existsSync15, readFileSync as readFileSync17, readdirSync as readdirSync5, statSync as statSync6 } from "node:fs";
17213
+ import { join as join13 } from "node:path";
15792
17214
  async function runs(args2) {
15793
17215
  const json = args2.includes("--json");
15794
17216
  const watch = args2.includes("--watch");
@@ -15872,8 +17294,8 @@ function listActiveRuns() {
15872
17294
  return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
15873
17295
  }
15874
17296
  function readSpend(sinceMs) {
15875
- if (!existsSync13(SPEND_PATH)) return [];
15876
- const lines = readFileSync16(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
17297
+ if (!existsSync15(SPEND_PATH)) return [];
17298
+ const lines = readFileSync17(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
15877
17299
  const out = [];
15878
17300
  for (const line of lines) {
15879
17301
  try {
@@ -15994,23 +17416,23 @@ function ageLabel(ms) {
15994
17416
  return `${Math.floor(ms / 864e5)}d`;
15995
17417
  }
15996
17418
  function listTraceFiles() {
15997
- if (!existsSync13(RUNS_DIR2)) return [];
15998
- const entries2 = readdirSync4(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
17419
+ if (!existsSync15(RUNS_DIR2)) return [];
17420
+ const entries2 = readdirSync5(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
15999
17421
  return entries2.map((f) => {
16000
- const path5 = join11(RUNS_DIR2, f);
16001
- const st = statSync4(path5);
16002
- return { runId: f.replace(/\.jsonl$/, ""), path: path5, mtimeMs: st.mtimeMs };
17422
+ const path7 = join13(RUNS_DIR2, f);
17423
+ const st = statSync6(path7);
17424
+ return { runId: f.replace(/\.jsonl$/, ""), path: path7, mtimeMs: st.mtimeMs };
16003
17425
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
16004
17426
  }
16005
17427
  function resolveRunId(arg) {
16006
- if (!existsSync13(RUNS_DIR2)) return null;
17428
+ if (!existsSync15(RUNS_DIR2)) return null;
16007
17429
  if (arg === "latest") {
16008
17430
  const all2 = listTraceFiles();
16009
17431
  if (all2.length === 0) return null;
16010
17432
  return { runId: all2[0].runId, path: all2[0].path };
16011
17433
  }
16012
- const exact = join11(RUNS_DIR2, `${arg}.jsonl`);
16013
- if (existsSync13(exact)) return { runId: arg, path: exact };
17434
+ const exact = join13(RUNS_DIR2, `${arg}.jsonl`);
17435
+ if (existsSync15(exact)) return { runId: arg, path: exact };
16014
17436
  const all = listTraceFiles();
16015
17437
  const matches = all.filter((r) => r.runId.includes(arg));
16016
17438
  if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
@@ -16021,8 +17443,8 @@ function resolveRunId(arg) {
16021
17443
  }
16022
17444
  return null;
16023
17445
  }
16024
- function readTrace(path5) {
16025
- return readFileSync16(path5, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
17446
+ function readTrace(path7) {
17447
+ return readFileSync17(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
16026
17448
  try {
16027
17449
  return JSON.parse(l);
16028
17450
  } catch {
@@ -16034,7 +17456,7 @@ async function inspect(arg, follow, json) {
16034
17456
  const r = resolveRunId(arg);
16035
17457
  if (!r) {
16036
17458
  console.error(`run not found: ${arg}`);
16037
- if (existsSync13(RUNS_DIR2)) {
17459
+ if (existsSync15(RUNS_DIR2)) {
16038
17460
  const all = listTraceFiles().slice(0, 5);
16039
17461
  if (all.length > 0) {
16040
17462
  console.error(`
@@ -16054,13 +17476,13 @@ recent runs:`);
16054
17476
  const events = readTrace(r.path);
16055
17477
  printTrace(r.runId, events);
16056
17478
  if (!follow) return;
16057
- let lastSize = statSync4(r.path).size;
17479
+ let lastSize = statSync6(r.path).size;
16058
17480
  let lastIdx = events.length;
16059
17481
  console.log("\n \u27F6 following \xB7 ^C to quit\n");
16060
17482
  process.on("SIGINT", () => process.exit(0));
16061
17483
  while (true) {
16062
17484
  await new Promise((res) => setTimeout(res, 500));
16063
- const st = statSync4(r.path);
17485
+ const st = statSync6(r.path);
16064
17486
  if (st.size === lastSize) continue;
16065
17487
  lastSize = st.size;
16066
17488
  const all = readTrace(r.path);
@@ -16204,7 +17626,7 @@ async function main() {
16204
17626
  case "version":
16205
17627
  case "--version":
16206
17628
  case "-v":
16207
- console.log(`fleetlens ${"0.11.2"}`);
17629
+ console.log(`fleetlens ${"0.12.1"}`);
16208
17630
  break;
16209
17631
  case "help":
16210
17632
  case "--help":