fleetlens 0.15.2 → 0.15.3

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 (159) hide show
  1. package/app/apps/web/.next/BUILD_ID +1 -1
  2. package/app/apps/web/.next/app-path-routes-manifest.json +1 -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 +6 -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.nft.json +1 -1
  14. package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
  16. package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
  17. package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
  18. package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
  19. package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
  20. package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
  21. package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
  22. package/app/apps/web/.next/server/app/api/projects/open-folder/route/app-paths-manifest.json +3 -0
  23. package/app/apps/web/.next/server/app/api/projects/open-folder/route/build-manifest.json +9 -0
  24. package/app/apps/web/.next/server/app/api/projects/open-folder/route/server-reference-manifest.json +4 -0
  25. package/app/apps/web/.next/server/app/api/projects/open-folder/route.js +7 -0
  26. package/app/apps/web/.next/server/app/api/projects/open-folder/route.js.map +5 -0
  27. package/app/apps/web/.next/server/app/api/projects/open-folder/route.js.nft.json +1 -0
  28. package/app/apps/web/.next/server/app/api/projects/open-folder/route_client-reference-manifest.js +3 -0
  29. package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
  30. package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
  31. package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
  32. package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
  33. package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  34. package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
  35. package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
  36. package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
  37. package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
  38. package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
  39. package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
  40. package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
  41. package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  42. package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
  43. package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
  44. package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
  45. package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
  46. package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
  47. package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  48. package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
  49. package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
  50. package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -1
  51. package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
  52. package/app/apps/web/.next/server/app/projects/[slug]/page.js +1 -1
  53. package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  54. package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  55. package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
  56. package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  57. package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
  58. package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
  59. package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  60. package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  61. package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
  62. package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  63. package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  64. package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  65. package/app/apps/web/.next/server/app/team/onboarding/page.js.nft.json +1 -1
  66. package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +1 -1
  67. package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
  68. package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
  69. package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
  70. package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
  71. package/app/apps/web/.next/server/app-paths-manifest.json +1 -0
  72. package/app/apps/web/.next/server/chunks/02dz_web__next-internal_server_app_api_projects_open-folder_route_actions_0m~419c.js +3 -0
  73. package/app/apps/web/.next/server/chunks/[root-of-the-server]__12iid50._.js +3 -0
  74. package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +1 -1
  75. package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +1 -1
  76. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0.zquoa._.js +1 -1
  77. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__03svi~4._.js +8 -0
  78. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04eq6z2._.js +1 -1
  79. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04il6m2._.js +1 -1
  80. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__08l86e-._.js +1 -1
  81. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__09rjz7_._.js +1 -1
  82. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ar_8wr._.js +1 -1
  83. package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__10~b4bf._.js → [root-of-the-server]__0blm9gz._.js} +3 -3
  84. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0c00i76._.js +1 -1
  85. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0e.gxk3._.js +1 -1
  86. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0g-tomj._.js +3 -0
  87. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0i.q-1h._.js +1 -1
  88. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0k1x-c9._.js +1 -1
  89. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0lz4a~g._.js +1 -1
  90. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0o1_g.~._.js +1 -1
  91. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0p1x6v2._.js +1 -1
  92. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0r4tks8._.js +1 -1
  93. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +1 -1
  94. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0stu~~r._.js +1 -1
  95. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0tejjy_._.js +1 -1
  96. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0u39afl._.js +1 -1
  97. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0ufi3.w._.js +1 -1
  98. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0xy1qim._.js +1 -1
  99. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~.f_3z._.js +3 -3
  100. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__10srpu0._.js +1 -1
  101. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js +1 -1
  102. package/app/apps/web/.next/server/chunks/ssr/_02r-a1a._.js +8 -0
  103. package/app/apps/web/.next/server/chunks/ssr/_0k62ejd._.js +8 -0
  104. package/app/apps/web/.next/server/chunks/ssr/{_0wj750k._.js → _0t~mx7w._.js} +2 -2
  105. package/app/apps/web/.next/server/chunks/ssr/{_0kajk31._.js → _0whg~r-._.js} +2 -2
  106. package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
  107. package/app/apps/web/.next/server/chunks/ssr/_13jdm1g._.js +3 -0
  108. package/app/apps/web/.next/server/chunks/ssr/apps_web_app_sessions_sessions-grid_tsx_0bri5x.._.js +1 -1
  109. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0txtsv5._.js +1 -1
  110. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
  111. package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
  112. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_12vc-v-._.js +3 -0
  113. package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_0mx_509._.js +1 -1
  114. package/app/apps/web/.next/server/functions-config-manifest.json +1 -0
  115. package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
  116. package/app/apps/web/.next/server/middleware-manifest.json +5 -5
  117. package/app/apps/web/.next/server/pages/500.html +1 -1
  118. package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
  119. package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
  120. package/app/apps/web/.next/static/chunks/{0~qdw1b2uz._5.js → 044mtrzh7d7va.js} +3 -3
  121. package/app/apps/web/.next/static/chunks/05b0dn.r00hq1.js +1 -0
  122. package/app/apps/web/.next/static/chunks/{14vx702c32kn6.js → 0_0~~ipv90vm3.js} +1 -1
  123. package/app/apps/web/.next/static/chunks/0_ujxc0.z66xb.js +14 -0
  124. package/app/apps/web/.next/static/chunks/0awkd5df28gvj.js +6 -0
  125. package/app/apps/web/.next/static/chunks/0bhwd68o~-xc_.js +1 -0
  126. package/app/apps/web/.next/static/chunks/{0m7dd-2zd9vl2.js → 0eoc4yy0s0gpe.js} +1 -1
  127. package/app/apps/web/.next/static/chunks/0rsp61c8wb.sx.js +6 -0
  128. package/app/apps/web/.next/static/chunks/{03rd.3cc_t~yf.js → 0s~0-8l~_kqnf.js} +1 -1
  129. package/app/apps/web/.next/static/chunks/0y3448zrint0k.js +6 -0
  130. package/app/apps/web/app/api/projects/open-folder/route.ts +60 -0
  131. package/app/apps/web/app/projects/[slug]/local-folders-button.tsx +406 -0
  132. package/app/apps/web/app/projects/[slug]/page.tsx +155 -20
  133. package/app/apps/web/app/projects/page.tsx +2 -2
  134. package/app/apps/web/app/sessions/[id]/page.tsx +4 -1
  135. package/app/apps/web/app/sessions/[id]/session-view/header-stats.tsx +81 -0
  136. package/app/apps/web/app/sessions/[id]/session-view.tsx +11 -0
  137. package/app/apps/web/app/sessions/sessions-grid.tsx +56 -25
  138. package/app/apps/web/lib/changelog-data.generated.ts +1 -1
  139. package/app/apps/web/lib/entries-index.ts +4 -4
  140. package/app/apps/web/package.json +1 -1
  141. package/app/apps/web/tsconfig.tsbuildinfo +1 -1
  142. package/dist/daemon-worker.js +405 -174
  143. package/dist/index.js +476 -245
  144. package/package.json +1 -1
  145. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0a7n44-._.js +0 -3
  146. package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0lhwp-k._.js +0 -8
  147. package/app/apps/web/.next/server/chunks/ssr/_0s3n5mz._.js +0 -8
  148. package/app/apps/web/.next/server/chunks/ssr/_12mbgs5._.js +0 -3
  149. package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0b-4-4j._.js +0 -8
  150. package/app/apps/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0cepfi8._.js +0 -3
  151. package/app/apps/web/.next/static/chunks/03gy1evbn94qu.js +0 -6
  152. package/app/apps/web/.next/static/chunks/0d2x-wfu.m0-z.js +0 -6
  153. package/app/apps/web/.next/static/chunks/0i77er85v.rj..js +0 -1
  154. package/app/apps/web/.next/static/chunks/0nqklmbs5s3ax.js +0 -6
  155. package/app/apps/web/.next/static/chunks/0tirv_vo6q8uc.js +0 -1
  156. package/app/apps/web/.next/static/chunks/0u6gxpqhl0gc7.js +0 -14
  157. /package/app/apps/web/.next/static/{mTj8nKiazosAKJec15dLe → lIz-6F0SEIL9sgFO3XTJp}/_buildManifest.js +0 -0
  158. /package/app/apps/web/.next/static/{mTj8nKiazosAKJec15dLe → lIz-6F0SEIL9sgFO3XTJp}/_clientMiddlewareManifest.js +0 -0
  159. /package/app/apps/web/.next/static/{mTj8nKiazosAKJec15dLe → lIz-6F0SEIL9sgFO3XTJp}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -148,11 +148,22 @@ function worktreeName(projectName) {
148
148
  return ss.workspaceName;
149
149
  return null;
150
150
  }
151
- function projectRepoName(projectName) {
151
+ function projectKey(projectName) {
152
152
  const canonical = canonicalProjectName(projectName);
153
153
  const segs = canonical.replace(/\/+$/, "").split("/").filter(Boolean);
154
154
  return segs[segs.length - 1] || canonical;
155
155
  }
156
+ function sessionProjectKey(s) {
157
+ return s.repoName ?? projectKey(s.projectName);
158
+ }
159
+ function buildProjectKeyResolver(sessions) {
160
+ const alias = /* @__PURE__ */ new Map();
161
+ for (const s of sessions) {
162
+ if (s.repoName)
163
+ alias.set(projectKey(s.projectName), s.repoName);
164
+ }
165
+ return (s) => s.repoName ?? alias.get(projectKey(s.projectName)) ?? projectKey(s.projectName);
166
+ }
156
167
  function makeDay(date) {
157
168
  return {
158
169
  date,
@@ -587,8 +598,9 @@ function summarizeBursts(bursts) {
587
598
  }
588
599
  function groupByProject(sessions) {
589
600
  const map = /* @__PURE__ */ new Map();
601
+ const keyOf = buildProjectKeyResolver(sessions);
590
602
  for (const s of sessions) {
591
- const repo = projectRepoName(s.projectName);
603
+ const repo = keyOf(s);
592
604
  const key = repo;
593
605
  let cur = map.get(key);
594
606
  if (!cur) {
@@ -617,7 +629,7 @@ function groupByProject(sessions) {
617
629
  p.metrics = highLevelMetrics(p.sessions);
618
630
  const wtNames = /* @__PURE__ */ new Set();
619
631
  for (const s of p.sessions) {
620
- const wt = worktreeName(s.projectName);
632
+ const wt = s.worktreeName ?? worktreeName(s.projectName) ?? (s.cwd ? worktreeName(s.cwd) : null);
621
633
  if (wt)
622
634
  wtNames.add(wt);
623
635
  }
@@ -636,7 +648,7 @@ function groupByProject(sessions) {
636
648
  }
637
649
  return Array.from(map.values()).sort((a, b) => (b.lastActiveMs ?? 0) - (a.lastActiveMs ?? 0));
638
650
  }
639
- var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, SUPERSET_MARKER, UUID_SEG_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
651
+ var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, SUPERSET_MARKER, UUID_SEG_RE, projectRepoName, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
640
652
  var init_analytics = __esm({
641
653
  "../parser/dist/analytics.js"() {
642
654
  "use strict";
@@ -649,6 +661,7 @@ var init_analytics = __esm({
649
661
  CONDUCTOR_RE = /\/conductor\/workspaces\/[^/]+\/([^/]+)(?:\/|$)/;
650
662
  SUPERSET_MARKER = "/.superset/worktrees/";
651
663
  UUID_SEG_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
664
+ projectRepoName = projectKey;
652
665
  PR_CREATE_RE = /gh\s+pr\s+create\b/i;
653
666
  PR_NUMBER_RE = /#(\d+)/;
654
667
  TITLE_FLAG_RE = /--title\s+["']([^"']+)["']/;
@@ -1447,6 +1460,187 @@ var init_parser = __esm({
1447
1460
  }
1448
1461
  });
1449
1462
 
1463
+ // ../parser/dist/git-project.js
1464
+ import { existsSync, readFileSync as readFileSync2, realpathSync, statSync } from "node:fs";
1465
+ import { homedir } from "node:os";
1466
+ import { basename, dirname as dirname2, isAbsolute, join, resolve } from "node:path";
1467
+ function resolveGitDir(root, dotGitText) {
1468
+ const m = dotGitText.match(/^gitdir:\s*(.+)\s*$/m);
1469
+ if (!m)
1470
+ return void 0;
1471
+ const gitDir = m[1].trim();
1472
+ return isAbsolute(gitDir) ? gitDir : resolve(root, gitDir);
1473
+ }
1474
+ function resolveCommonDir(gitDir) {
1475
+ const file = join(gitDir, "commondir");
1476
+ if (!existsSync(file))
1477
+ return void 0;
1478
+ const common = readFileSync2(file, "utf8").trim();
1479
+ if (!common)
1480
+ return void 0;
1481
+ return isAbsolute(common) ? common : resolve(gitDir, common);
1482
+ }
1483
+ function dotGitInfoFor(root) {
1484
+ const dotGit = join(root, ".git");
1485
+ const st = statSync(dotGit, { throwIfNoEntry: false });
1486
+ if (!st)
1487
+ return null;
1488
+ if (st.isDirectory())
1489
+ return { root, gitDir: dotGit, commonDir: dotGit };
1490
+ const gitDir = resolveGitDir(root, readFileSync2(dotGit, "utf8"));
1491
+ if (!gitDir)
1492
+ return { root };
1493
+ return { root, gitDir, commonDir: resolveCommonDir(gitDir) };
1494
+ }
1495
+ function walkBoundary(start2) {
1496
+ const home = realpathOrSelf(homedir());
1497
+ return start2 === home || start2.startsWith(`${home}/`) ? home : void 0;
1498
+ }
1499
+ function nearestDotGit(start2) {
1500
+ if (!start2 || !isAbsolute(start2))
1501
+ return null;
1502
+ const boundary = walkBoundary(start2);
1503
+ for (let dir = start2.replace(/\/+$/, "") || start2; ; dir = dirname2(dir)) {
1504
+ if (dir === boundary)
1505
+ return null;
1506
+ const info = dotGitInfoFor(dir);
1507
+ if (info)
1508
+ return info;
1509
+ const parent = dirname2(dir);
1510
+ if (parent === dir)
1511
+ return null;
1512
+ }
1513
+ }
1514
+ function originUrl(configText) {
1515
+ let inOrigin = false;
1516
+ for (const line of configText.split("\n")) {
1517
+ const t = line.trim();
1518
+ if (t.startsWith("[")) {
1519
+ inOrigin = /^\[remote\s+"origin"\]/.test(t);
1520
+ continue;
1521
+ }
1522
+ if (!inOrigin)
1523
+ continue;
1524
+ const m = t.match(/^url\s*=\s*(.+)$/);
1525
+ if (m)
1526
+ return m[1].trim();
1527
+ }
1528
+ return void 0;
1529
+ }
1530
+ function parseRemote(url) {
1531
+ const m = url.match(REMOTE_URL_RE);
1532
+ if (!m)
1533
+ return void 0;
1534
+ const host = m[1];
1535
+ const segs = m[2].split("/").filter(Boolean);
1536
+ if (segs.length < 2)
1537
+ return void 0;
1538
+ const name = segs[segs.length - 1];
1539
+ const owner = segs.slice(0, -1).join("/");
1540
+ return { host, owner, name, url, webUrl: `https://${host}/${owner}/${name}` };
1541
+ }
1542
+ function remoteFor(git) {
1543
+ const dir = git.commonDir ?? git.gitDir;
1544
+ if (!dir)
1545
+ return void 0;
1546
+ const config = join(dir, "config");
1547
+ if (!existsSync(config))
1548
+ return void 0;
1549
+ const url = originUrl(readFileSync2(config, "utf8"));
1550
+ return url ? parseRemote(url) : void 0;
1551
+ }
1552
+ function headBranch(gitDir) {
1553
+ if (!gitDir)
1554
+ return void 0;
1555
+ const head = join(gitDir, "HEAD");
1556
+ if (!existsSync(head))
1557
+ return void 0;
1558
+ const t = readFileSync2(head, "utf8").trim();
1559
+ const m = t.match(/^ref:\s*refs\/heads\/(.+)$/);
1560
+ return m ? m[1] : `detached @ ${t.slice(0, 7)}`;
1561
+ }
1562
+ function defaultBranch(commonDir) {
1563
+ if (!commonDir)
1564
+ return void 0;
1565
+ const head = join(commonDir, "refs", "remotes", "origin", "HEAD");
1566
+ if (existsSync(head)) {
1567
+ const m = readFileSync2(head, "utf8").trim().match(/refs\/remotes\/origin\/(.+)$/);
1568
+ if (m)
1569
+ return m[1];
1570
+ }
1571
+ const packed = join(commonDir, "packed-refs");
1572
+ if (existsSync(packed)) {
1573
+ const m = readFileSync2(packed, "utf8").match(/refs\/remotes\/origin\/(\S+)/);
1574
+ if (m && m[1] !== "HEAD")
1575
+ return m[1];
1576
+ }
1577
+ return void 0;
1578
+ }
1579
+ function readGitFolder(path7) {
1580
+ if (!existsSync(path7))
1581
+ return { exists: false, isWorktree: false };
1582
+ try {
1583
+ const git = nearestDotGit(realpathOrSelf(path7));
1584
+ if (!git)
1585
+ return { exists: true, isWorktree: false };
1586
+ const projectRoot = projectRootFromCommonDir(git.commonDir);
1587
+ const isWorktree = !!projectRoot && realpathOrSelf(projectRoot) !== realpathOrSelf(git.root);
1588
+ return {
1589
+ exists: true,
1590
+ isWorktree,
1591
+ branch: headBranch(git.gitDir),
1592
+ defaultBranch: defaultBranch(git.commonDir),
1593
+ remote: remoteFor(git)
1594
+ };
1595
+ } catch {
1596
+ return { exists: true, isWorktree: false };
1597
+ }
1598
+ }
1599
+ function projectRootFromCommonDir(commonDir) {
1600
+ if (!commonDir)
1601
+ return void 0;
1602
+ return basename(commonDir) === ".git" ? dirname2(commonDir) : void 0;
1603
+ }
1604
+ function realpathOrSelf(p) {
1605
+ try {
1606
+ return realpathSync(p);
1607
+ } catch {
1608
+ return p;
1609
+ }
1610
+ }
1611
+ function resolveProjectIdentity(cwd) {
1612
+ const normalized = realpathOrSelf(cwd.replace(/\/{2,}/g, "/"));
1613
+ try {
1614
+ const git = nearestDotGit(normalized);
1615
+ if (git) {
1616
+ const projectRoot = realpathOrSelf(projectRootFromCommonDir(git.commonDir) ?? git.root);
1617
+ const gitRoot = realpathOrSelf(git.root);
1618
+ const wt2 = projectRoot !== gitRoot ? worktreeName(normalized) ?? basename(git.root) : void 0;
1619
+ const identity = { projectName: projectRoot };
1620
+ if (wt2)
1621
+ identity.worktreeName = wt2;
1622
+ const remote = remoteFor(git);
1623
+ if (remote) {
1624
+ identity.remote = remote;
1625
+ identity.repoName = remote.name;
1626
+ }
1627
+ return identity;
1628
+ }
1629
+ } catch {
1630
+ }
1631
+ const projectName = canonicalProjectName(normalized);
1632
+ const wt = worktreeName(normalized) ?? void 0;
1633
+ return wt ? { projectName, worktreeName: wt } : { projectName };
1634
+ }
1635
+ var REMOTE_URL_RE;
1636
+ var init_git_project = __esm({
1637
+ "../parser/dist/git-project.js"() {
1638
+ "use strict";
1639
+ init_analytics();
1640
+ REMOTE_URL_RE = /^(?:(?:https?|ssh|git):\/\/)?(?:[^@/]+@)?([^/:]+)[:/](.+?)(?:\.git)?\/?$/;
1641
+ }
1642
+ });
1643
+
1450
1644
  // ../parser/dist/team.js
1451
1645
  function groupByTeam(sessions, details) {
1452
1646
  const byTeam = /* @__PURE__ */ new Map();
@@ -1915,12 +2109,16 @@ async function getCachedMeta(f) {
1915
2109
  const sessionId = sessionIdFromFileName(f.fileName);
1916
2110
  const projectDirPath = path.dirname(f.fullPath);
1917
2111
  const wf = await scanWorkflowAggregate(projectDirPath, sessionId);
2112
+ const cwd = meta.cwd ?? decodeProjectName(f.projectDir);
2113
+ const project = resolveProjectIdentity(cwd);
1918
2114
  const full = {
1919
2115
  ...meta,
1920
2116
  id: sessionId,
1921
2117
  filePath: f.fullPath,
1922
2118
  projectDir: f.projectDir,
1923
- projectName: meta.cwd ?? decodeProjectName(f.projectDir),
2119
+ projectName: project.projectName,
2120
+ worktreeName: project.worktreeName,
2121
+ repoName: project.repoName,
1924
2122
  ...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
1925
2123
  ...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
1926
2124
  };
@@ -1941,12 +2139,16 @@ async function getCachedDetail(f) {
1941
2139
  const sessionId = sessionIdFromFileName(f.fileName);
1942
2140
  await applySubagentUsage(meta, rawLines, f);
1943
2141
  const wf = await scanWorkflowAggregate(path.dirname(f.fullPath), sessionId);
2142
+ const cwd = meta.cwd ?? decodeProjectName(f.projectDir);
2143
+ const project = resolveProjectIdentity(cwd);
1944
2144
  const detail = {
1945
2145
  ...meta,
1946
2146
  id: sessionId,
1947
2147
  filePath: f.fullPath,
1948
2148
  projectDir: f.projectDir,
1949
- projectName: meta.cwd ?? decodeProjectName(f.projectDir),
2149
+ projectName: project.projectName,
2150
+ worktreeName: project.worktreeName,
2151
+ repoName: project.repoName,
1950
2152
  events,
1951
2153
  ...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
1952
2154
  ...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
@@ -2438,19 +2640,25 @@ async function listProjects(root = DEFAULT_ROOT) {
2438
2640
  cur.lastActiveMs = f.mtimeMs;
2439
2641
  byRawDir.set(f.projectDir, cur);
2440
2642
  }
2441
- const cwdForProject = (dir) => {
2643
+ const cachedIdentityForProject = (dir) => {
2442
2644
  for (const [, entry] of metaCache.entries()) {
2443
- if (entry.meta.projectDir === dir && entry.meta.cwd) {
2444
- return entry.meta.cwd;
2645
+ if (entry.meta.projectDir === dir) {
2646
+ return {
2647
+ cwd: entry.meta.cwd,
2648
+ projectName: entry.meta.projectName,
2649
+ worktreeName: entry.meta.worktreeName
2650
+ };
2445
2651
  }
2446
2652
  }
2447
2653
  return void 0;
2448
2654
  };
2449
2655
  const canonicalMap = /* @__PURE__ */ new Map();
2450
2656
  for (const [rawDir, { count, lastActiveMs }] of byRawDir) {
2451
- const cwdOrDecoded = cwdForProject(rawDir) ?? decodeProjectName(rawDir);
2452
- const repo = projectRepoName(cwdOrDecoded);
2453
- const wt = worktreeName(cwdOrDecoded);
2657
+ const cached = cachedIdentityForProject(rawDir);
2658
+ const cwdOrDecoded = cached?.cwd ?? decodeProjectName(rawDir);
2659
+ const projectName = cached?.projectName ?? canonicalProjectName(cwdOrDecoded);
2660
+ const wt = cached?.worktreeName ?? worktreeName(cwdOrDecoded) ?? void 0;
2661
+ const repo = projectKey(projectName);
2454
2662
  const agg = canonicalMap.get(repo) ?? {
2455
2663
  canonicalName: repo,
2456
2664
  count: 0,
@@ -2516,6 +2724,7 @@ var init_claude_code = __esm({
2516
2724
  "use strict";
2517
2725
  init_parser();
2518
2726
  init_analytics();
2727
+ init_git_project();
2519
2728
  init_team();
2520
2729
  init_agent_metadata();
2521
2730
  init_calibration();
@@ -2822,13 +3031,16 @@ function parseRollout(file, lines) {
2822
3031
  const activeSegments = computeActiveSegments2(tsMs);
2823
3032
  const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
2824
3033
  const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
2825
- const projectName = cwd ? canonicalProjectName(cwd) : "(unknown)";
3034
+ const project = cwd ? resolveProjectIdentity(cwd) : void 0;
3035
+ const projectName = project?.projectName ?? "(unknown)";
2826
3036
  const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : "(unknown)";
2827
3037
  const meta = {
2828
3038
  agent: "codex",
2829
3039
  id: file.sessionId,
2830
3040
  filePath: file.filePath,
2831
3041
  projectName,
3042
+ worktreeName: project?.worktreeName,
3043
+ repoName: project?.repoName,
2832
3044
  projectDir,
2833
3045
  sessionId: file.sessionId,
2834
3046
  firstTimestamp,
@@ -2987,6 +3199,7 @@ var init_codex = __esm({
2987
3199
  "../parser/dist/codex.js"() {
2988
3200
  "use strict";
2989
3201
  init_analytics();
3202
+ init_git_project();
2990
3203
  init_user_input();
2991
3204
  DEFAULT_CODEX_ROOT = path2.join(os2.homedir(), ".codex", "sessions");
2992
3205
  ROLLOUT_RE = /^rollout-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})-([0-9a-f-]+)\.jsonl$/;
@@ -3366,13 +3579,16 @@ async function parseSession(file) {
3366
3579
  const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
3367
3580
  const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
3368
3581
  const sessionId = metaRec.sessionId ?? file.filenameId;
3369
- const projectName = cwd ? canonicalProjectName(cwd) : file.slug;
3582
+ const project = cwd ? resolveProjectIdentity(cwd) : void 0;
3583
+ const projectName = project?.projectName ?? file.slug;
3370
3584
  const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.slug;
3371
3585
  const meta = {
3372
3586
  agent: "gemini",
3373
3587
  id: sessionId,
3374
3588
  filePath: file.filePath,
3375
3589
  projectName,
3590
+ worktreeName: project?.worktreeName,
3591
+ repoName: project?.repoName,
3376
3592
  projectDir,
3377
3593
  sessionId,
3378
3594
  firstTimestamp,
@@ -3486,6 +3702,7 @@ var init_gemini = __esm({
3486
3702
  "../parser/dist/gemini.js"() {
3487
3703
  "use strict";
3488
3704
  init_analytics();
3705
+ init_git_project();
3489
3706
  init_user_input();
3490
3707
  DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
3491
3708
  GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
@@ -3759,13 +3976,16 @@ async function parseSession2(file) {
3759
3976
  const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
3760
3977
  const sessionId = file.conversationId;
3761
3978
  const cwd = file.cwd;
3762
- const projectName = cwd ? canonicalProjectName(cwd) : file.conversationId;
3979
+ const project = cwd ? resolveProjectIdentity(cwd) : void 0;
3980
+ const projectName = project?.projectName ?? file.conversationId;
3763
3981
  const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.conversationId;
3764
3982
  const meta = {
3765
3983
  agent: "antigravity",
3766
3984
  id: sessionId,
3767
3985
  filePath: file.filePath,
3768
3986
  projectName,
3987
+ worktreeName: project?.worktreeName,
3988
+ repoName: project?.repoName,
3769
3989
  projectDir,
3770
3990
  sessionId,
3771
3991
  firstTimestamp,
@@ -3872,6 +4092,7 @@ var init_antigravity = __esm({
3872
4092
  "../parser/dist/antigravity.js"() {
3873
4093
  "use strict";
3874
4094
  init_analytics();
4095
+ init_git_project();
3875
4096
  init_user_input();
3876
4097
  DEFAULT_ANTIGRAVITY_ROOT = path4.join(os4.homedir(), ".gemini", "antigravity-cli");
3877
4098
  IDLE_GAP_MS3 = 3 * 60 * 1e3;
@@ -3991,8 +4212,10 @@ function resolveProject(meta, spaceIdToPath) {
3991
4212
  if (!projectPath) {
3992
4213
  return { projectName: "cowork:unspaced", projectDir: "cowork-unspaced" };
3993
4214
  }
4215
+ const project = resolveProjectIdentity(projectPath);
3994
4216
  return {
3995
- projectName: canonicalProjectName(projectPath),
4217
+ projectName: project.projectName,
4218
+ worktreeName: project.worktreeName,
3996
4219
  projectDir: projectPath.replace(/^\//, "-").replace(/\//g, "-"),
3997
4220
  cwd: projectPath
3998
4221
  };
@@ -4219,8 +4442,8 @@ var DEFAULT_COWORK_ROOT, SESSION_ID_RE, spacesCache, metaCache5, detailCache5;
4219
4442
  var init_cowork = __esm({
4220
4443
  "../parser/dist/cowork.js"() {
4221
4444
  "use strict";
4222
- init_analytics();
4223
4445
  init_claude_code();
4446
+ init_git_project();
4224
4447
  init_parser();
4225
4448
  DEFAULT_COWORK_ROOT = defaultCoworkRoot();
4226
4449
  SESSION_ID_RE = /^local_[0-9a-f-]+$/;
@@ -4231,21 +4454,21 @@ var init_cowork = __esm({
4231
4454
  });
4232
4455
 
4233
4456
  // ../parser/dist/team-config.js
4234
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, renameSync } from "node:fs";
4235
- import { join } from "node:path";
4236
- function shouldSyncProject(repoName, sp) {
4457
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, renameSync } from "node:fs";
4458
+ import { join as join2 } from "node:path";
4459
+ function shouldSyncProject(projectKey2, sp) {
4237
4460
  if (!sp)
4238
4461
  return true;
4239
- if (sp.excluded.includes(repoName))
4462
+ if (sp.excluded.includes(projectKey2))
4240
4463
  return false;
4241
- if (sp.included.includes(repoName))
4464
+ if (sp.included.includes(projectKey2))
4242
4465
  return true;
4243
4466
  return sp.autoIncludeNew;
4244
4467
  }
4245
4468
  function readTeamConfig(dir) {
4246
4469
  const d = dir ?? cclensHome();
4247
4470
  try {
4248
- return JSON.parse(readFileSync2(join(d, CONFIG_FILE), "utf8"));
4471
+ return JSON.parse(readFileSync3(join2(d, CONFIG_FILE), "utf8"));
4249
4472
  } catch {
4250
4473
  return null;
4251
4474
  }
@@ -4253,14 +4476,14 @@ function readTeamConfig(dir) {
4253
4476
  function writeTeamConfig(config, dir) {
4254
4477
  const d = dir ?? cclensHome();
4255
4478
  mkdirSync2(d, { recursive: true });
4256
- const tmp = join(d, `${CONFIG_FILE}.${process.pid}.tmp`);
4479
+ const tmp = join2(d, `${CONFIG_FILE}.${process.pid}.tmp`);
4257
4480
  writeFileSync2(tmp, JSON.stringify(config, null, 2), { mode: 384 });
4258
- renameSync(tmp, join(d, CONFIG_FILE));
4481
+ renameSync(tmp, join2(d, CONFIG_FILE));
4259
4482
  }
4260
4483
  function clearTeamConfig(dir) {
4261
4484
  const d = dir ?? cclensHome();
4262
4485
  try {
4263
- unlinkSync2(join(d, CONFIG_FILE));
4486
+ unlinkSync2(join2(d, CONFIG_FILE));
4264
4487
  } catch {
4265
4488
  }
4266
4489
  }
@@ -4326,8 +4549,10 @@ __export(fs_exports, {
4326
4549
  loadTeamForSession: () => loadTeamForSession,
4327
4550
  loadUsageByDay: () => loadUsageByDay,
4328
4551
  loadWorkflowAgentDetail: () => loadWorkflowAgentDetail,
4552
+ readGitFolder: () => readGitFolder,
4329
4553
  readJsonlFile: () => readJsonlFile,
4330
4554
  readTeamConfig: () => readTeamConfig,
4555
+ resolveProjectIdentity: () => resolveProjectIdentity,
4331
4556
  sessionIdFromFileName: () => sessionIdFromFileName,
4332
4557
  shouldSyncProject: () => shouldSyncProject,
4333
4558
  walkJsonlFiles: () => walkJsonlFiles,
@@ -4603,6 +4828,7 @@ var init_fs = __esm({
4603
4828
  init_antigravity();
4604
4829
  init_cowork();
4605
4830
  init_claude_code();
4831
+ init_git_project();
4606
4832
  init_codex();
4607
4833
  init_gemini();
4608
4834
  init_antigravity();
@@ -4681,13 +4907,13 @@ __export(server_exports, {
4681
4907
  stopServer: () => stopServer
4682
4908
  });
4683
4909
  import { spawn } from "node:child_process";
4684
- import { join as join2, dirname as dirname2 } from "node:path";
4910
+ import { join as join3, dirname as dirname3 } from "node:path";
4685
4911
  import { fileURLToPath } from "node:url";
4686
- import { existsSync } from "node:fs";
4687
- import { homedir } from "node:os";
4912
+ import { existsSync as existsSync2 } from "node:fs";
4913
+ import { homedir as homedir2 } from "node:os";
4688
4914
  function appDir() {
4689
- const here = dirname2(fileURLToPath(import.meta.url));
4690
- return join2(here, "..", "app", "apps", "web");
4915
+ const here = dirname3(fileURLToPath(import.meta.url));
4916
+ return join3(here, "..", "app", "apps", "web");
4691
4917
  }
4692
4918
  function getServerStatus() {
4693
4919
  cleanStalePid(PID_FILE, SERVER_MARKERS);
@@ -4698,7 +4924,7 @@ function getServerStatus() {
4698
4924
  return { running: false };
4699
4925
  }
4700
4926
  function isServerStale(status2) {
4701
- return status2.running === true && status2.version !== "0.15.2";
4927
+ return status2.running === true && status2.version !== "0.15.3";
4702
4928
  }
4703
4929
  async function ensureCurrentServer(opts = {}) {
4704
4930
  const status2 = getServerStatus();
@@ -4731,15 +4957,15 @@ async function ensureCurrentServer(opts = {}) {
4731
4957
  }
4732
4958
  async function startServer(opts = {}) {
4733
4959
  const port = opts.port ?? (parseInt(process.env.CCLENS_PORT ?? "", 10) || DEFAULT_PORT);
4734
- const serverJs = join2(appDir(), "server.js");
4735
- if (!existsSync(serverJs)) {
4960
+ const serverJs = join3(appDir(), "server.js");
4961
+ if (!existsSync2(serverJs)) {
4736
4962
  throw new Error(`Server not found at ${serverJs}. Reinstall with: npm install -g fleetlens`);
4737
4963
  }
4738
4964
  const portInUse = await checkPort(port);
4739
4965
  if (portInUse) {
4740
4966
  throw new Error(`Port ${port} is in use. Use --port to specify a different port.`);
4741
4967
  }
4742
- const dataDir = join2(homedir(), ".claude", "projects");
4968
+ const dataDir = join3(homedir2(), ".claude", "projects");
4743
4969
  const child = spawn(process.execPath, [serverJs], {
4744
4970
  detached: true,
4745
4971
  stdio: "ignore",
@@ -4754,7 +4980,7 @@ async function startServer(opts = {}) {
4754
4980
  });
4755
4981
  child.unref();
4756
4982
  const pid = child.pid;
4757
- writePid(PID_FILE, pid, port, "0.15.2");
4983
+ writePid(PID_FILE, pid, port, "0.15.3");
4758
4984
  await waitForHealth(`http://localhost:${port}`, 3e4);
4759
4985
  return { pid, port };
4760
4986
  }
@@ -4773,11 +4999,11 @@ function stopServer() {
4773
4999
  }
4774
5000
  async function checkPort(port) {
4775
5001
  const { createServer } = await import("node:net");
4776
- return new Promise((resolve3) => {
5002
+ return new Promise((resolve4) => {
4777
5003
  const server = createServer();
4778
- server.once("error", () => resolve3(true));
5004
+ server.once("error", () => resolve4(true));
4779
5005
  server.once("listening", () => {
4780
- server.close(() => resolve3(false));
5006
+ server.close(() => resolve4(false));
4781
5007
  });
4782
5008
  server.listen(port, "localhost");
4783
5009
  });
@@ -4825,15 +5051,15 @@ __export(storage_exports, {
4825
5051
  latestSnapshot: () => latestSnapshot,
4826
5052
  readSnapshots: () => readSnapshots
4827
5053
  });
4828
- import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, existsSync as existsSync2 } from "node:fs";
4829
- import { dirname as dirname3 } from "node:path";
5054
+ import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync4, existsSync as existsSync3 } from "node:fs";
5055
+ import { dirname as dirname4 } from "node:path";
4830
5056
  function appendSnapshot(filePath, snapshot) {
4831
- mkdirSync3(dirname3(filePath), { recursive: true });
5057
+ mkdirSync3(dirname4(filePath), { recursive: true });
4832
5058
  appendFileSync(filePath, JSON.stringify(snapshot) + "\n", "utf8");
4833
5059
  }
4834
5060
  function readSnapshots(filePath) {
4835
- if (!existsSync2(filePath)) return [];
4836
- const content = readFileSync3(filePath, "utf8");
5061
+ if (!existsSync3(filePath)) return [];
5062
+ const content = readFileSync4(filePath, "utf8");
4837
5063
  const snapshots = [];
4838
5064
  for (const line of content.split("\n")) {
4839
5065
  if (!line.trim()) continue;
@@ -4871,9 +5097,9 @@ __export(daemon_exports, {
4871
5097
  stopDaemonSilent: () => stopDaemonSilent
4872
5098
  });
4873
5099
  import { spawn as spawn2 } from "node:child_process";
4874
- import { join as join3, dirname as dirname4 } from "node:path";
5100
+ import { join as join4, dirname as dirname5 } from "node:path";
4875
5101
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4876
- import { existsSync as existsSync3, statSync, readFileSync as readFileSync4 } from "node:fs";
5102
+ import { existsSync as existsSync4, statSync as statSync2, readFileSync as readFileSync5 } from "node:fs";
4877
5103
  function startDaemonSilent() {
4878
5104
  cleanStalePid(DAEMON_PID, DAEMON_MARKERS);
4879
5105
  const existing = readPid(DAEMON_PID);
@@ -4881,7 +5107,7 @@ function startDaemonSilent() {
4881
5107
  return { started: false, pid: existing.pid, alreadyRunning: true };
4882
5108
  }
4883
5109
  const script = workerPath();
4884
- if (!existsSync3(script)) {
5110
+ if (!existsSync4(script)) {
4885
5111
  return {
4886
5112
  started: false,
4887
5113
  pid: null,
@@ -4915,7 +5141,7 @@ function getDaemonStatusInfo() {
4915
5141
  const running = entry !== null && isProcessAlive(entry.pid, DAEMON_MARKERS);
4916
5142
  const latest = latestSnapshot(USAGE_LOG);
4917
5143
  const lastSnapshotAgeMs = latest ? Date.now() - new Date(latest.captured_at).getTime() : null;
4918
- const usageLogSize = existsSync3(USAGE_LOG) ? statSync(USAGE_LOG).size : null;
5144
+ const usageLogSize = existsSync4(USAGE_LOG) ? statSync2(USAGE_LOG).size : null;
4919
5145
  return {
4920
5146
  running,
4921
5147
  pid: running ? entry.pid : null,
@@ -4925,8 +5151,8 @@ function getDaemonStatusInfo() {
4925
5151
  };
4926
5152
  }
4927
5153
  function workerPath() {
4928
- const here = dirname4(fileURLToPath2(import.meta.url));
4929
- return join3(here, "daemon-worker.js");
5154
+ const here = dirname5(fileURLToPath2(import.meta.url));
5155
+ return join4(here, "daemon-worker.js");
4930
5156
  }
4931
5157
  async function daemon(args2) {
4932
5158
  const sub = args2[0] ?? "status";
@@ -4991,11 +5217,11 @@ function daemonStatus() {
4991
5217
  }
4992
5218
  }
4993
5219
  function daemonLogs() {
4994
- if (!existsSync3(DAEMON_LOG)) {
5220
+ if (!existsSync4(DAEMON_LOG)) {
4995
5221
  console.log("No daemon logs yet.");
4996
5222
  return;
4997
5223
  }
4998
- const content = readFileSync4(DAEMON_LOG, "utf8");
5224
+ const content = readFileSync5(DAEMON_LOG, "utf8");
4999
5225
  const lines = content.trim().split("\n").slice(-20);
5000
5226
  for (const line of lines) process.stdout.write(line + "\n");
5001
5227
  }
@@ -5015,8 +5241,8 @@ var init_daemon = __esm({
5015
5241
 
5016
5242
  // src/updater.ts
5017
5243
  import { execSync, spawnSync } from "node:child_process";
5018
- import { existsSync as existsSync4, readFileSync as readFileSync5, realpathSync } from "node:fs";
5019
- import { dirname as dirname5, join as join4 } from "node:path";
5244
+ import { existsSync as existsSync5, readFileSync as readFileSync6, realpathSync as realpathSync2 } from "node:fs";
5245
+ import { dirname as dirname6, join as join5 } from "node:path";
5020
5246
  function shouldUpdate(local, remote) {
5021
5247
  const l = local.split(".").map(Number);
5022
5248
  const r = remote.split(".").map(Number);
@@ -5058,15 +5284,15 @@ function verifyInstalledVersion() {
5058
5284
  encoding: "utf8",
5059
5285
  timeout: 5e3
5060
5286
  }).trim();
5061
- const pkgPath = join4(globalRoot, PACKAGE_NAME, "package.json");
5062
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
5287
+ const pkgPath = join5(globalRoot, PACKAGE_NAME, "package.json");
5288
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
5063
5289
  if (!pkg.version) {
5064
5290
  return { ok: false, reason: `no version field in ${pkgPath}` };
5065
5291
  }
5066
5292
  return {
5067
5293
  ok: true,
5068
5294
  installedVersion: pkg.version,
5069
- installedPath: join4(globalRoot, PACKAGE_NAME)
5295
+ installedPath: join5(globalRoot, PACKAGE_NAME)
5070
5296
  };
5071
5297
  } catch (err) {
5072
5298
  return { ok: false, reason: err.message };
@@ -5123,28 +5349,28 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
5123
5349
  console.warn(
5124
5350
  ` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
5125
5351
  );
5126
- } else if (verify.installedVersion !== "0.15.2") {
5352
+ } else if (verify.installedVersion !== "0.15.3") {
5127
5353
  console.log(
5128
- ` \u2192 This process is still running ${"0.15.2"}. Next invocation will use ${verify.installedVersion}.`
5354
+ ` \u2192 This process is still running ${"0.15.3"}. Next invocation will use ${verify.installedVersion}.`
5129
5355
  );
5130
5356
  }
5131
5357
  }
5132
5358
  function resolvesIntoPackage(binPath, packagePath) {
5133
5359
  try {
5134
- const real = realpathSync(binPath);
5360
+ const real = realpathSync2(binPath);
5135
5361
  if (real.startsWith(packagePath)) return true;
5136
5362
  } catch {
5137
5363
  }
5138
- const binPrefix = dirname5(dirname5(binPath));
5139
- const installPrefix = dirname5(dirname5(dirname5(packagePath)));
5364
+ const binPrefix = dirname6(dirname6(binPath));
5365
+ const installPrefix = dirname6(dirname6(dirname6(packagePath)));
5140
5366
  return binPrefix === installPrefix;
5141
5367
  }
5142
5368
  function reExec() {
5143
5369
  const verify = verifyInstalledVersion();
5144
5370
  let script = process.argv[1] ?? "";
5145
5371
  if (verify.ok) {
5146
- const candidate = join4(verify.installedPath, "dist", "index.js");
5147
- if (existsSync4(candidate)) script = candidate;
5372
+ const candidate = join5(verify.installedPath, "dist", "index.js");
5373
+ if (existsSync5(candidate)) script = candidate;
5148
5374
  }
5149
5375
  const result = spawnSync(process.argv[0], [script, ...process.argv.slice(2)], {
5150
5376
  stdio: "inherit",
@@ -5160,14 +5386,14 @@ async function getUpdateAvailability() {
5160
5386
  if (isDevMode()) return null;
5161
5387
  const latest = await fetchLatestVersion();
5162
5388
  if (latest === null) return {
5163
- current: "0.15.2",
5389
+ current: "0.15.3",
5164
5390
  latest: null,
5165
5391
  updateAvailable: false
5166
5392
  };
5167
5393
  return {
5168
- current: "0.15.2",
5394
+ current: "0.15.3",
5169
5395
  latest,
5170
- updateAvailable: shouldUpdate("0.15.2", latest)
5396
+ updateAvailable: shouldUpdate("0.15.3", latest)
5171
5397
  };
5172
5398
  }
5173
5399
  async function checkForUpdate() {
@@ -5257,7 +5483,7 @@ async function restartServices(state) {
5257
5483
  }
5258
5484
  async function forceUpdate() {
5259
5485
  const latest = await fetchLatestVersion();
5260
- const current = "0.15.2";
5486
+ const current = "0.15.3";
5261
5487
  if (latest === null) {
5262
5488
  console.error("Could not reach npm registry. Check your network.");
5263
5489
  process.exit(1);
@@ -5309,27 +5535,27 @@ __export(autostart_exports, {
5309
5535
  maybePromptAutostart: () => maybePromptAutostart,
5310
5536
  recordOptOut: () => recordOptOut
5311
5537
  });
5312
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync, readFileSync as readFileSync6, realpathSync as realpathSync2 } from "node:fs";
5313
- import { homedir as homedir2 } from "node:os";
5314
- import { join as join5, dirname as dirname6 } from "node:path";
5538
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync, readFileSync as readFileSync7, realpathSync as realpathSync3 } from "node:fs";
5539
+ import { homedir as homedir3 } from "node:os";
5540
+ import { join as join6, dirname as dirname7 } from "node:path";
5315
5541
  import { execFile } from "node:child_process";
5316
5542
  import { promisify } from "node:util";
5317
5543
  import { createInterface } from "node:readline";
5318
5544
  function plistPath() {
5319
- return join5(homedir2(), "Library", "LaunchAgents", `${LABEL}.plist`);
5545
+ return join6(homedir3(), "Library", "LaunchAgents", `${LABEL}.plist`);
5320
5546
  }
5321
5547
  function isMac() {
5322
5548
  return process.platform === "darwin";
5323
5549
  }
5324
5550
  function isAutostartInstalled() {
5325
- return isMac() && existsSync5(plistPath());
5551
+ return isMac() && existsSync6(plistPath());
5326
5552
  }
5327
5553
  function isStalePlistContent(content) {
5328
5554
  return content.includes("<string>daemon</string>");
5329
5555
  }
5330
5556
  function installedPlistIsStale() {
5331
5557
  try {
5332
- return isStalePlistContent(readFileSync6(plistPath(), "utf8"));
5558
+ return isStalePlistContent(readFileSync7(plistPath(), "utf8"));
5333
5559
  } catch {
5334
5560
  return false;
5335
5561
  }
@@ -5337,7 +5563,7 @@ function installedPlistIsStale() {
5337
5563
  function resolveScriptPath() {
5338
5564
  const argv1 = process.argv[1] ?? "";
5339
5565
  try {
5340
- return realpathSync2(argv1);
5566
+ return realpathSync3(argv1);
5341
5567
  } catch {
5342
5568
  return argv1;
5343
5569
  }
@@ -5380,7 +5606,7 @@ async function installAutostart() {
5380
5606
  const scriptPath = resolveScriptPath();
5381
5607
  const logPath = cclensPath("daemon-autostart.log");
5382
5608
  const p = plistPath();
5383
- mkdirSync4(dirname6(p), { recursive: true });
5609
+ mkdirSync4(dirname7(p), { recursive: true });
5384
5610
  writeFileSync3(p, buildPlist({ nodePath, scriptPath, logPath }), "utf8");
5385
5611
  await runLaunchctl(["unload", p]).catch(() => {
5386
5612
  });
@@ -5401,7 +5627,7 @@ async function uninstallAutostart() {
5401
5627
  }
5402
5628
  const p = plistPath();
5403
5629
  recordOptOut();
5404
- if (!existsSync5(p)) {
5630
+ if (!existsSync6(p)) {
5405
5631
  console.log("Autostart is not installed \u2014 nothing to remove. Noted your opt-out; team join won't enable it.");
5406
5632
  return;
5407
5633
  }
@@ -5434,7 +5660,7 @@ async function statusAutostart() {
5434
5660
  return;
5435
5661
  }
5436
5662
  const p = plistPath();
5437
- const present = existsSync5(p);
5663
+ const present = existsSync6(p);
5438
5664
  let loaded = false;
5439
5665
  try {
5440
5666
  const { stdout } = await execFileAsync("launchctl", ["list"]);
@@ -5449,7 +5675,7 @@ function promptFlagPath() {
5449
5675
  }
5450
5676
  function readFlags() {
5451
5677
  try {
5452
- return JSON.parse(readFileSync6(promptFlagPath(), "utf8"));
5678
+ return JSON.parse(readFileSync7(promptFlagPath(), "utf8"));
5453
5679
  } catch {
5454
5680
  return {};
5455
5681
  }
@@ -5457,7 +5683,7 @@ function readFlags() {
5457
5683
  function writeFlags(patch) {
5458
5684
  const p = promptFlagPath();
5459
5685
  try {
5460
- mkdirSync4(dirname6(p), { recursive: true });
5686
+ mkdirSync4(dirname7(p), { recursive: true });
5461
5687
  writeFileSync3(p, JSON.stringify({ ...readFlags(), ...patch }, null, 2), "utf8");
5462
5688
  } catch {
5463
5689
  }
@@ -5475,13 +5701,13 @@ function recordOptOut() {
5475
5701
  writeFlags({ optedOut: true });
5476
5702
  }
5477
5703
  function promptYesNo(question, defaultYes) {
5478
- return new Promise((resolve3) => {
5704
+ return new Promise((resolve4) => {
5479
5705
  const rl = createInterface({ input: process.stdin, output: process.stdout });
5480
5706
  rl.question(question, (answer) => {
5481
5707
  rl.close();
5482
5708
  const a = answer.trim().toLowerCase();
5483
- if (a === "") return resolve3(defaultYes);
5484
- resolve3(a === "y" || a === "yes");
5709
+ if (a === "") return resolve4(defaultYes);
5710
+ resolve4(a === "y" || a === "yes");
5485
5711
  });
5486
5712
  });
5487
5713
  }
@@ -5670,7 +5896,7 @@ async function status() {
5670
5896
  console.log(`Server: running on ${url} (PID ${server.pid}, v${ver})`);
5671
5897
  if (isServerStale(server)) {
5672
5898
  console.log(
5673
- ` \u26A0 serving stale ${ver} (CLI is ${"0.15.2"}) \u2014 run 'fleetlens start' to restart on the current version`
5899
+ ` \u26A0 serving stale ${ver} (CLI is ${"0.15.3"}) \u2014 run 'fleetlens start' to restart on the current version`
5674
5900
  );
5675
5901
  }
5676
5902
  } else {
@@ -5752,9 +5978,9 @@ var init_update = __esm({
5752
5978
 
5753
5979
  // src/usage/token.ts
5754
5980
  import { execFileSync as execFileSync2 } from "node:child_process";
5755
- import { readFileSync as readFileSync7 } from "node:fs";
5756
- import { homedir as homedir3, platform } from "node:os";
5757
- import { join as join6 } from "node:path";
5981
+ import { readFileSync as readFileSync8 } from "node:fs";
5982
+ import { homedir as homedir4, platform } from "node:os";
5983
+ import { join as join7 } from "node:path";
5758
5984
  function readOAuthCredentials() {
5759
5985
  if (platform() === "darwin") {
5760
5986
  return readFromMacKeychain() ?? readFromCredentialsFile();
@@ -5775,12 +6001,12 @@ function readFromMacKeychain() {
5775
6001
  }
5776
6002
  function readFromCredentialsFile() {
5777
6003
  const candidates = [
5778
- join6(homedir3(), ".claude", ".credentials.json"),
5779
- join6(homedir3(), ".config", "claude", "credentials.json")
6004
+ join7(homedir4(), ".claude", ".credentials.json"),
6005
+ join7(homedir4(), ".config", "claude", "credentials.json")
5780
6006
  ];
5781
6007
  for (const path7 of candidates) {
5782
6008
  try {
5783
- const blob = readFileSync7(path7, "utf8");
6009
+ const blob = readFileSync8(path7, "utf8");
5784
6010
  const creds = extractCredentials(blob);
5785
6011
  if (creds) return creds;
5786
6012
  } catch {
@@ -6780,6 +7006,7 @@ __export(dist_exports, {
6780
7006
  buildGanttDay: () => buildGanttDay,
6781
7007
  buildMegaRows: () => buildMegaRows,
6782
7008
  buildPresentation: () => buildPresentation,
7009
+ buildProjectKeyResolver: () => buildProjectKeyResolver,
6783
7010
  buildSpendIndex: () => buildSpendIndex,
6784
7011
  calendarMonth: () => calendarMonth,
6785
7012
  calendarWeek: () => calendarWeek,
@@ -6808,10 +7035,12 @@ __export(dist_exports, {
6808
7035
  predictAnchored: () => predictAnchored,
6809
7036
  priorCalendarMonth: () => priorCalendarMonth,
6810
7037
  priorCalendarWeek: () => priorCalendarWeek,
7038
+ projectKey: () => projectKey,
6811
7039
  projectRepoName: () => projectRepoName,
6812
7040
  rowPrimaryIndex: () => rowPrimaryIndex,
6813
7041
  sessionAirTimeMs: () => sessionAirTimeMs,
6814
7042
  sessionDay: () => sessionDay,
7043
+ sessionProjectKey: () => sessionProjectKey,
6815
7044
  stripFrameworkBoilerplate: () => stripFrameworkBoilerplate,
6816
7045
  summarizeBursts: () => summarizeBursts,
6817
7046
  toLocalDay: () => toLocalDay,
@@ -7426,6 +7655,7 @@ function buildEntries(sessionDetail) {
7426
7655
  const entries2 = [];
7427
7656
  const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
7428
7657
  const sessionFallbackProject = canonicalProjectName(sessionDetail.projectName ?? "");
7658
+ const trustSessionProject = !!sessionDetail.worktreeName;
7429
7659
  for (const [local_day, dayEvents] of byDay) {
7430
7660
  if (dayEvents.length === 0)
7431
7661
  continue;
@@ -7490,7 +7720,7 @@ function buildEntries(sessionDetail) {
7490
7720
  const finalAgentRaw = agg.finalAgent ?? "";
7491
7721
  const final_agent = trunc(minimizeImages(finalAgentRaw), 400);
7492
7722
  let project = sessionFallbackProject;
7493
- if (agg.cwdCounts.size > 0) {
7723
+ if (!trustSessionProject && agg.cwdCounts.size > 0) {
7494
7724
  const best = [...agg.cwdCounts.entries()].sort((a, b) => b[1] - a[1])[0];
7495
7725
  project = canonicalProjectName(best[0]);
7496
7726
  }
@@ -7600,11 +7830,11 @@ var init_dist2 = __esm({
7600
7830
  });
7601
7831
 
7602
7832
  // ../entries/dist/digest-fs.js
7603
- import { readFileSync as readFileSync8, readdirSync, writeFileSync as writeFileSync4, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "node:fs";
7604
- import { dirname as dirname7, join as join7 } from "node:path";
7833
+ import { readFileSync as readFileSync9, readdirSync, writeFileSync as writeFileSync4, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync5, existsSync as existsSync7 } from "node:fs";
7834
+ import { dirname as dirname8, join as join8 } from "node:path";
7605
7835
  function parseDigestFile(path7, expectedVersion) {
7606
7836
  try {
7607
- const parsed = JSON.parse(readFileSync8(path7, "utf8"));
7837
+ const parsed = JSON.parse(readFileSync9(path7, "utf8"));
7608
7838
  if (!parsed || typeof parsed !== "object")
7609
7839
  return null;
7610
7840
  if (parsed.version !== expectedVersion)
@@ -7625,22 +7855,22 @@ function digestsDir() {
7625
7855
  }
7626
7856
  function __setDigestsDirForTest(path7) {
7627
7857
  digestsDirCached = path7;
7628
- mkdirSync5(join7(path7, "day"), { recursive: true });
7629
- mkdirSync5(join7(path7, "week"), { recursive: true });
7630
- mkdirSync5(join7(path7, "month"), { recursive: true });
7858
+ mkdirSync5(join8(path7, "day"), { recursive: true });
7859
+ mkdirSync5(join8(path7, "week"), { recursive: true });
7860
+ mkdirSync5(join8(path7, "month"), { recursive: true });
7631
7861
  }
7632
7862
  function dayDigestPath(date) {
7633
- return join7(digestsDir(), "day", `${date}.json`);
7863
+ return join8(digestsDir(), "day", `${date}.json`);
7634
7864
  }
7635
7865
  function weekDigestPath(monday) {
7636
- return join7(digestsDir(), "week", `${monday}.json`);
7866
+ return join8(digestsDir(), "week", `${monday}.json`);
7637
7867
  }
7638
7868
  function monthDigestPath(yearMonth) {
7639
- return join7(digestsDir(), "month", `${yearMonth}.json`);
7869
+ return join8(digestsDir(), "month", `${yearMonth}.json`);
7640
7870
  }
7641
7871
  function writeDayDigest(digest2) {
7642
7872
  const final = dayDigestPath(digest2.key);
7643
- mkdirSync5(dirname7(final), { recursive: true });
7873
+ mkdirSync5(dirname8(final), { recursive: true });
7644
7874
  const tmp = `${final}.tmp`;
7645
7875
  writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7646
7876
  if (process.platform !== "win32") {
@@ -7653,7 +7883,7 @@ function writeDayDigest(digest2) {
7653
7883
  }
7654
7884
  function readDayDigest(date) {
7655
7885
  const p = dayDigestPath(date);
7656
- if (!existsSync6(p))
7886
+ if (!existsSync7(p))
7657
7887
  return null;
7658
7888
  return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
7659
7889
  }
@@ -7676,7 +7906,7 @@ function __clearTodayCacheForTest() {
7676
7906
  }
7677
7907
  function writeWeekDigest(digest2) {
7678
7908
  const final = weekDigestPath(digest2.key);
7679
- mkdirSync5(dirname7(final), { recursive: true });
7909
+ mkdirSync5(dirname8(final), { recursive: true });
7680
7910
  const tmp = `${final}.tmp`;
7681
7911
  writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7682
7912
  if (process.platform !== "win32") {
@@ -7689,13 +7919,13 @@ function writeWeekDigest(digest2) {
7689
7919
  }
7690
7920
  function readWeekDigest(monday) {
7691
7921
  const p = weekDigestPath(monday);
7692
- if (!existsSync6(p))
7922
+ if (!existsSync7(p))
7693
7923
  return null;
7694
7924
  return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
7695
7925
  }
7696
7926
  function listWeekDigestKeys() {
7697
- const dir = join7(digestsDir(), "week");
7698
- if (!existsSync6(dir))
7927
+ const dir = join8(digestsDir(), "week");
7928
+ if (!existsSync7(dir))
7699
7929
  return [];
7700
7930
  return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}-\d{2}$/.test(k));
7701
7931
  }
@@ -7713,7 +7943,7 @@ function setCurrentWeekDigestInCache(monday, digest2, nowMs) {
7713
7943
  }
7714
7944
  function writeMonthDigest(digest2) {
7715
7945
  const final = monthDigestPath(digest2.key);
7716
- mkdirSync5(dirname7(final), { recursive: true });
7946
+ mkdirSync5(dirname8(final), { recursive: true });
7717
7947
  const tmp = `${final}.tmp`;
7718
7948
  writeFileSync4(tmp, JSON.stringify(digest2, null, 2), "utf8");
7719
7949
  if (process.platform !== "win32") {
@@ -7726,13 +7956,13 @@ function writeMonthDigest(digest2) {
7726
7956
  }
7727
7957
  function readMonthDigest(yearMonth) {
7728
7958
  const p = monthDigestPath(yearMonth);
7729
- if (!existsSync6(p))
7959
+ if (!existsSync7(p))
7730
7960
  return null;
7731
7961
  return parseDigestFile(p, CURRENT_MONTH_DIGEST_SCHEMA_VERSION);
7732
7962
  }
7733
7963
  function listMonthDigestKeys() {
7734
- const dir = join7(digestsDir(), "month");
7735
- if (!existsSync6(dir))
7964
+ const dir = join8(digestsDir(), "month");
7965
+ if (!existsSync7(dir))
7736
7966
  return [];
7737
7967
  return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}$/.test(k));
7738
7968
  }
@@ -7794,9 +8024,9 @@ __export(fs_exports2, {
7794
8024
  writeMonthDigest: () => writeMonthDigest,
7795
8025
  writeWeekDigest: () => writeWeekDigest
7796
8026
  });
7797
- import { readFileSync as readFileSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, renameSync as renameSync3, existsSync as existsSync7 } from "node:fs";
8027
+ import { readFileSync as readFileSync10, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, renameSync as renameSync3, existsSync as existsSync8 } from "node:fs";
7798
8028
  import { randomBytes } from "node:crypto";
7799
- import { join as join8 } from "node:path";
8029
+ import { join as join9 } from "node:path";
7800
8030
  function entriesDir() {
7801
8031
  if (entriesDirCached)
7802
8032
  return entriesDirCached;
@@ -7809,7 +8039,7 @@ function __setEntriesDirForTest(path7) {
7809
8039
  mkdirSync6(path7, { recursive: true });
7810
8040
  }
7811
8041
  function pathFor(sessionId, localDay2) {
7812
- return join8(entriesDir(), `${entryKey(sessionId, localDay2)}.json`);
8042
+ return join9(entriesDir(), `${entryKey(sessionId, localDay2)}.json`);
7813
8043
  }
7814
8044
  function tmpPathFor(final) {
7815
8045
  return `${final}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
@@ -7853,17 +8083,17 @@ function writeEntryPreservingEnrichment(fresh) {
7853
8083
  }
7854
8084
  function readEntry(sessionId, localDay2) {
7855
8085
  const p = pathFor(sessionId, localDay2);
7856
- if (!existsSync7(p))
8086
+ if (!existsSync8(p))
7857
8087
  return null;
7858
- const raw = readFileSync9(p, "utf8");
8088
+ const raw = readFileSync10(p, "utf8");
7859
8089
  return JSON.parse(raw);
7860
8090
  }
7861
8091
  function entryExists(sessionId, localDay2) {
7862
- return existsSync7(pathFor(sessionId, localDay2));
8092
+ return existsSync8(pathFor(sessionId, localDay2));
7863
8093
  }
7864
8094
  function listEntryKeys() {
7865
8095
  const dir = entriesDir();
7866
- if (!existsSync7(dir))
8096
+ if (!existsSync8(dir))
7867
8097
  return [];
7868
8098
  return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
7869
8099
  }
@@ -12142,9 +12372,9 @@ RESPOND WITH ONLY VALID JSON (no prose, no code fence):
12142
12372
  });
12143
12373
 
12144
12374
  // ../entries/dist/tmux-runner.js
12145
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6, existsSync as existsSync8, readdirSync as readdirSync3, realpathSync as realpathSync3, readFileSync as readFileSync10, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
12146
- import { join as join9 } from "node:path";
12147
- import { homedir as homedir4 } from "node:os";
12375
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6, existsSync as existsSync9, readdirSync as readdirSync3, realpathSync as realpathSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
12376
+ import { join as join10 } from "node:path";
12377
+ import { homedir as homedir5 } from "node:os";
12148
12378
  import { spawnSync as spawnSync2 } from "node:child_process";
12149
12379
  function which(bin) {
12150
12380
  const r = spawnSync2("/usr/bin/env", ["which", bin], { encoding: "utf8" });
@@ -12160,16 +12390,16 @@ function tmuxRunnerAvailable() {
12160
12390
  return { ok: true };
12161
12391
  }
12162
12392
  function runtimeCwd() {
12163
- const dir = join9(homedir4(), ".cclens", "runtime");
12164
- if (!existsSync8(dir))
12393
+ const dir = join10(homedir5(), ".cclens", "runtime");
12394
+ if (!existsSync9(dir))
12165
12395
  mkdirSync7(dir, { recursive: true });
12166
- return realpathSync3(dir);
12396
+ return realpathSync4(dir);
12167
12397
  }
12168
12398
  function ensureRuntimeCwdTrusted(cwd) {
12169
- const cfgPath = join9(homedir4(), ".claude.json");
12399
+ const cfgPath = join10(homedir5(), ".claude.json");
12170
12400
  let cfg;
12171
12401
  try {
12172
- cfg = JSON.parse(readFileSync10(cfgPath, "utf8"));
12402
+ cfg = JSON.parse(readFileSync11(cfgPath, "utf8"));
12173
12403
  } catch {
12174
12404
  return;
12175
12405
  }
@@ -12211,9 +12441,9 @@ async function runClaudeUnderTmuxImpl(args2) {
12211
12441
  ensureRuntimeCwdTrusted(cwd);
12212
12442
  const runId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12213
12443
  const sessionName = `cclens-${runId}`;
12214
- const systemFile = join9(cwd, `system-${runId}.txt`);
12215
- const userFile = join9(cwd, `user-${runId}.txt`);
12216
- const wrapper = join9(cwd, `run-${runId}.sh`);
12444
+ const systemFile = join10(cwd, `system-${runId}.txt`);
12445
+ const userFile = join10(cwd, `user-${runId}.txt`);
12446
+ const wrapper = join10(cwd, `run-${runId}.sh`);
12217
12447
  writeFileSync6(systemFile, args2.systemPrompt);
12218
12448
  writeFileSync6(userFile, args2.reminder ? `${args2.userPrompt}
12219
12449
 
@@ -12302,7 +12532,7 @@ function snapshotAllTranscripts() {
12302
12532
  return out;
12303
12533
  }
12304
12534
  for (const sub of subs) {
12305
- const dir = join9(root, sub);
12535
+ const dir = join10(root, sub);
12306
12536
  let files;
12307
12537
  try {
12308
12538
  files = readdirSync3(dir);
@@ -12311,7 +12541,7 @@ function snapshotAllTranscripts() {
12311
12541
  }
12312
12542
  for (const f of files) {
12313
12543
  if (f.endsWith(".jsonl"))
12314
- out.add(join9(dir, f));
12544
+ out.add(join10(dir, f));
12315
12545
  }
12316
12546
  }
12317
12547
  return out;
@@ -12319,7 +12549,7 @@ function snapshotAllTranscripts() {
12319
12549
  function readJsonlCwd(path7, maxLines = 8) {
12320
12550
  let raw;
12321
12551
  try {
12322
- raw = readFileSync10(path7, "utf8");
12552
+ raw = readFileSync11(path7, "utf8");
12323
12553
  } catch {
12324
12554
  return void 0;
12325
12555
  }
@@ -12352,7 +12582,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12352
12582
  subs = [];
12353
12583
  }
12354
12584
  for (const sub of subs) {
12355
- const dir = join9(root, sub);
12585
+ const dir = join10(root, sub);
12356
12586
  let files;
12357
12587
  try {
12358
12588
  files = readdirSync3(dir);
@@ -12362,7 +12592,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12362
12592
  for (const f of files) {
12363
12593
  if (!f.endsWith(".jsonl"))
12364
12594
  continue;
12365
- const full = join9(dir, f);
12595
+ const full = join10(dir, f);
12366
12596
  if (existingBefore.has(full))
12367
12597
  continue;
12368
12598
  if (readJsonlCwd(full) === targetCwd)
@@ -12376,7 +12606,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
12376
12606
  function parseTranscript2(path7, defaultModel) {
12377
12607
  let raw;
12378
12608
  try {
12379
- raw = readFileSync10(path7, "utf8");
12609
+ raw = readFileSync11(path7, "utf8");
12380
12610
  } catch {
12381
12611
  return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
12382
12612
  }
@@ -12436,7 +12666,7 @@ function cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath) {
12436
12666
  }
12437
12667
  for (const f of [`system-${runId}.txt`, `user-${runId}.txt`, `run-${runId}.sh`]) {
12438
12668
  try {
12439
- unlinkSync3(join9(cwd, f));
12669
+ unlinkSync3(join10(cwd, f));
12440
12670
  } catch {
12441
12671
  }
12442
12672
  }
@@ -12464,17 +12694,17 @@ var init_tmux_runner = __esm({
12464
12694
  }
12465
12695
  };
12466
12696
  mutex = Promise.resolve();
12467
- PROJECTS_ROOT = () => join9(homedir4(), ".claude", "projects");
12697
+ PROJECTS_ROOT = () => join10(homedir5(), ".claude", "projects");
12468
12698
  }
12469
12699
  });
12470
12700
 
12471
12701
  // ../entries/dist/llm-runner.js
12472
12702
  import { spawn as spawn3 } from "node:child_process";
12473
- import { mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "node:fs";
12474
- import { join as join10 } from "node:path";
12703
+ import { mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "node:fs";
12704
+ import { join as join11 } from "node:path";
12475
12705
  import { randomUUID } from "node:crypto";
12476
12706
  function ensureRunsDir() {
12477
- if (!existsSync9(RUNS_DIR)) {
12707
+ if (!existsSync10(RUNS_DIR)) {
12478
12708
  try {
12479
12709
  mkdirSync8(RUNS_DIR, { recursive: true });
12480
12710
  } catch {
@@ -12503,7 +12733,7 @@ function newRunId(kind) {
12503
12733
  return `${ts}_${kind}_${short}`;
12504
12734
  }
12505
12735
  function tracePath(runId) {
12506
- return join10(RUNS_DIR, `${runId}.jsonl`);
12736
+ return join11(RUNS_DIR, `${runId}.jsonl`);
12507
12737
  }
12508
12738
  function safeAppend(path7, line) {
12509
12739
  try {
@@ -12591,7 +12821,7 @@ async function runClaudeSubprocess(args2) {
12591
12821
  return runClaudePrintMode(args2);
12592
12822
  }
12593
12823
  function runClaudePrintMode(args2) {
12594
- return new Promise((resolve3, reject) => {
12824
+ return new Promise((resolve4, reject) => {
12595
12825
  ensureRunsDir();
12596
12826
  const kind = detectKindFromSystemPrompt(args2.systemPrompt);
12597
12827
  const runId = newRunId(kind);
@@ -12722,7 +12952,7 @@ ${args2.reminder}` : args2.userPrompt;
12722
12952
  reject(new Error(`claude exited ${code}: ${stderr.trim().slice(0, 300)}`));
12723
12953
  return;
12724
12954
  }
12725
- resolve3({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
12955
+ resolve4({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
12726
12956
  });
12727
12957
  proc.on("error", (err) => {
12728
12958
  safeAppend(trace, JSON.stringify({ _meta: { type: "spawn_error", run_id: runId, ts: (/* @__PURE__ */ new Date()).toISOString(), error: err.message } }) + "\n");
@@ -12919,8 +13149,8 @@ var init_enrich2 = __esm({
12919
13149
  });
12920
13150
 
12921
13151
  // ../entries/dist/budget.js
12922
- import { appendFileSync as appendFileSync3, readFileSync as readFileSync11, existsSync as existsSync10, mkdirSync as mkdirSync9 } from "node:fs";
12923
- import { dirname as dirname8 } from "node:path";
13152
+ import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, existsSync as existsSync11, mkdirSync as mkdirSync9 } from "node:fs";
13153
+ import { dirname as dirname9 } from "node:path";
12924
13154
  function spendPath() {
12925
13155
  if (spendPathCached)
12926
13156
  return spendPathCached;
@@ -12932,17 +13162,17 @@ function __setSpendPathForTest(path7) {
12932
13162
  }
12933
13163
  function appendSpend(record) {
12934
13164
  const p = spendPath();
12935
- mkdirSync9(dirname8(p), { recursive: true });
13165
+ mkdirSync9(dirname9(p), { recursive: true });
12936
13166
  appendFileSync3(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
12937
13167
  }
12938
13168
  function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
12939
13169
  const p = spendPath();
12940
- if (!existsSync10(p))
13170
+ if (!existsSync11(p))
12941
13171
  return 0;
12942
13172
  const year = now.getUTCFullYear();
12943
13173
  const month2 = now.getUTCMonth();
12944
13174
  let total = 0;
12945
- const raw = readFileSync11(p, "utf8");
13175
+ const raw = readFileSync12(p, "utf8");
12946
13176
  for (const line of raw.split("\n")) {
12947
13177
  if (!line)
12948
13178
  continue;
@@ -12971,7 +13201,7 @@ var init_budget = __esm({
12971
13201
  });
12972
13202
 
12973
13203
  // ../entries/dist/pipeline-lock.js
12974
- import { writeFileSync as writeFileSync8, unlinkSync as unlinkSync4, existsSync as existsSync11, readFileSync as readFileSync12, statSync as statSync2 } from "node:fs";
13204
+ import { writeFileSync as writeFileSync8, unlinkSync as unlinkSync4, existsSync as existsSync12, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
12975
13205
  function lockPath() {
12976
13206
  if (lockPathCached)
12977
13207
  return lockPathCached;
@@ -13016,13 +13246,13 @@ function pidAlive(pid) {
13016
13246
  }
13017
13247
  function interactiveLockFresh(nowMs) {
13018
13248
  const p = lockPath();
13019
- if (!existsSync11(p))
13249
+ if (!existsSync12(p))
13020
13250
  return false;
13021
13251
  try {
13022
- const mtime = statSync2(p).mtimeMs;
13252
+ const mtime = statSync3(p).mtimeMs;
13023
13253
  if (nowMs - mtime > STALE_MS)
13024
13254
  return false;
13025
- const pid = Number(readFileSync12(p, "utf8").trim());
13255
+ const pid = Number(readFileSync13(p, "utf8").trim());
13026
13256
  if (!Number.isFinite(pid) || pid <= 0)
13027
13257
  return false;
13028
13258
  if (!pidAlive(pid))
@@ -13128,8 +13358,8 @@ var init_queue = __esm({
13128
13358
  });
13129
13359
 
13130
13360
  // ../entries/dist/settings.js
13131
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync10, existsSync as existsSync12 } from "node:fs";
13132
- import { dirname as dirname9 } from "node:path";
13361
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync10, existsSync as existsSync13 } from "node:fs";
13362
+ import { dirname as dirname10 } from "node:path";
13133
13363
  function settingsPath() {
13134
13364
  if (settingsPathCached)
13135
13365
  return settingsPathCached;
@@ -13164,10 +13394,10 @@ function fromDisk(d) {
13164
13394
  }
13165
13395
  function readSettings() {
13166
13396
  const p = settingsPath();
13167
- if (!existsSync12(p))
13397
+ if (!existsSync13(p))
13168
13398
  return DEFAULT_SETTINGS;
13169
13399
  try {
13170
- const raw = readFileSync13(p, "utf8");
13400
+ const raw = readFileSync14(p, "utf8");
13171
13401
  return fromDisk(JSON.parse(raw));
13172
13402
  } catch {
13173
13403
  return DEFAULT_SETTINGS;
@@ -13175,7 +13405,7 @@ function readSettings() {
13175
13405
  }
13176
13406
  function writeSettings(s) {
13177
13407
  const p = settingsPath();
13178
- mkdirSync10(dirname9(p), { recursive: true });
13408
+ mkdirSync10(dirname10(p), { recursive: true });
13179
13409
  const tmp = `${p}.tmp`;
13180
13410
  writeFileSync9(tmp, JSON.stringify(toDisk(s), null, 2), { encoding: "utf8" });
13181
13411
  if (process.platform !== "win32") {
@@ -16918,8 +17148,8 @@ var init_config = __esm({
16918
17148
  });
16919
17149
 
16920
17150
  // src/perception/build-entries.ts
16921
- import { statSync as statSync3, readFileSync as readFileSync14 } from "node:fs";
16922
- import { basename, dirname as dirname10 } from "node:path";
17151
+ import { statSync as statSync4, readFileSync as readFileSync15 } from "node:fs";
17152
+ import { basename as basename2, dirname as dirname11 } from "node:path";
16923
17153
  function decodeProjectDirName(projectDir) {
16924
17154
  if (projectDir.startsWith("-")) {
16925
17155
  return "/" + projectDir.slice(1).replace(/-/g, "/");
@@ -16927,8 +17157,8 @@ function decodeProjectDirName(projectDir) {
16927
17157
  return projectDir.replace(/-/g, "/");
16928
17158
  }
16929
17159
  function buildEntriesForFile(filePath) {
16930
- const stat = statSync3(filePath);
16931
- const raw = readFileSync14(filePath, "utf8");
17160
+ const stat = statSync4(filePath);
17161
+ const raw = readFileSync15(filePath, "utf8");
16932
17162
  const rawLines = raw.split("\n").filter(Boolean).map((l) => {
16933
17163
  try {
16934
17164
  return JSON.parse(l);
@@ -16938,8 +17168,8 @@ function buildEntriesForFile(filePath) {
16938
17168
  }).filter((x) => x !== null);
16939
17169
  if (rawLines.length === 0) return null;
16940
17170
  const { meta, events } = parseTranscript(rawLines);
16941
- const fileName = basename(filePath);
16942
- const projectDir = basename(dirname10(filePath));
17171
+ const fileName = basename2(filePath);
17172
+ const projectDir = basename2(dirname11(filePath));
16943
17173
  const sessionId = fileName.replace(/\.jsonl$/, "");
16944
17174
  const sd = {
16945
17175
  ...meta,
@@ -17025,7 +17255,7 @@ function clipSegmentsToDay(segments, bounds) {
17025
17255
  }
17026
17256
  function filterSyncedSessions(sessions, syncProjects) {
17027
17257
  if (!syncProjects) return sessions;
17028
- return sessions.filter((s) => shouldSyncProject(projectRepoName(s.projectName), syncProjects));
17258
+ return sessions.filter((s) => shouldSyncProject(projectKey(s.projectName), syncProjects));
17029
17259
  }
17030
17260
  function sessionTouchesDay(s, day2) {
17031
17261
  const bounds = dayBoundsMs(day2);
@@ -17066,7 +17296,7 @@ function buildRichRollupBlocks(day2, daySessions, entries2, resolveRepo) {
17066
17296
  const projects = /* @__PURE__ */ new Map();
17067
17297
  for (const s of clippedSessions) {
17068
17298
  const canonical = canonicalProjectName(s.projectName);
17069
- const name = projectRepoName(s.projectName);
17299
+ const name = projectKey(s.projectName);
17070
17300
  const repo = resolveRepo?.(canonical) ?? sessionRepo.get(s.id);
17071
17301
  const key = repo ?? name;
17072
17302
  const ms = s.activeSegments.reduce((sum, seg) => sum + (seg.endMs - seg.startMs), 0);
@@ -17109,7 +17339,7 @@ function buildRichRollupBlocks(day2, daySessions, entries2, resolveRepo) {
17109
17339
  commits += e.numbers.commits;
17110
17340
  pushes += e.numbers.pushes;
17111
17341
  if (e.github_repos?.length) {
17112
- const key = sessionRepo.get(e.session_id) ?? projectRepoName(e.project);
17342
+ const key = sessionRepo.get(e.session_id) ?? projectKey(e.project);
17113
17343
  const set = projectRepos.get(key) ?? /* @__PURE__ */ new Set();
17114
17344
  for (const r of e.github_repos) set.add(r);
17115
17345
  projectRepos.set(key, set);
@@ -17193,7 +17423,7 @@ function buildIngestPayload(inputs) {
17193
17423
  return {
17194
17424
  ingestId: randomUUID2(),
17195
17425
  observedAt: (/* @__PURE__ */ new Date()).toISOString(),
17196
- cliVersion: "0.15.2",
17426
+ cliVersion: "0.15.3",
17197
17427
  ...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
17198
17428
  ...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
17199
17429
  ...richRollup ? { richRollup } : {},
@@ -17234,13 +17464,13 @@ var init_push = __esm({
17234
17464
  });
17235
17465
 
17236
17466
  // src/team/git-remote.ts
17237
- import { existsSync as existsSync13, readFileSync as readFileSync15, statSync as statSync4 } from "node:fs";
17238
- import { dirname as dirname11, isAbsolute, join as join11, resolve } from "node:path";
17467
+ import { existsSync as existsSync14, readFileSync as readFileSync16, statSync as statSync5 } from "node:fs";
17468
+ import { dirname as dirname12, isAbsolute as isAbsolute2, join as join12, resolve as resolve2 } from "node:path";
17239
17469
  function parseGithubRemote(url) {
17240
17470
  const m = url.trim().match(GITHUB_URL_RE);
17241
17471
  return m ? `${m[1]}/${m[2]}`.toLowerCase() : null;
17242
17472
  }
17243
- function originUrl(configText) {
17473
+ function originUrl2(configText) {
17244
17474
  let inOrigin = false;
17245
17475
  for (const line of configText.split("\n")) {
17246
17476
  const t = line.trim();
@@ -17255,36 +17485,36 @@ function originUrl(configText) {
17255
17485
  return null;
17256
17486
  }
17257
17487
  function gitConfigPathFor(dir) {
17258
- const dotGit = join11(dir, ".git");
17259
- const st = statSync4(dotGit, { throwIfNoEntry: false });
17488
+ const dotGit = join12(dir, ".git");
17489
+ const st = statSync5(dotGit, { throwIfNoEntry: false });
17260
17490
  if (!st) return null;
17261
- if (st.isDirectory()) return join11(dotGit, "config");
17262
- const m = readFileSync15(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
17491
+ if (st.isDirectory()) return join12(dotGit, "config");
17492
+ const m = readFileSync16(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
17263
17493
  if (!m) return null;
17264
- const gd = isAbsolute(m[1]) ? m[1] : resolve(dir, m[1]);
17265
- const commondirFile = join11(gd, "commondir");
17266
- if (existsSync13(commondirFile)) {
17267
- const common = readFileSync15(commondirFile, "utf8").trim();
17268
- return join11(isAbsolute(common) ? common : resolve(gd, common), "config");
17494
+ const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
17495
+ const commondirFile = join12(gd, "commondir");
17496
+ if (existsSync14(commondirFile)) {
17497
+ const common = readFileSync16(commondirFile, "utf8").trim();
17498
+ return join12(isAbsolute2(common) ? common : resolve2(gd, common), "config");
17269
17499
  }
17270
- return join11(gd, "config");
17500
+ return join12(gd, "config");
17271
17501
  }
17272
17502
  function createRepoResolver() {
17273
17503
  const cache = /* @__PURE__ */ new Map();
17274
17504
  return (dir) => {
17275
- if (!dir || !isAbsolute(dir)) return null;
17505
+ if (!dir || !isAbsolute2(dir)) return null;
17276
17506
  const hit = cache.get(dir);
17277
17507
  if (hit !== void 0) return hit;
17278
17508
  let repo = null;
17279
17509
  try {
17280
- for (let d = dir; ; d = dirname11(d)) {
17510
+ for (let d = dir; ; d = dirname12(d)) {
17281
17511
  const config = gitConfigPathFor(d);
17282
- if (config && existsSync13(config)) {
17283
- const url = originUrl(readFileSync15(config, "utf8"));
17512
+ if (config && existsSync14(config)) {
17513
+ const url = originUrl2(readFileSync16(config, "utf8"));
17284
17514
  repo = url ? parseGithubRemote(url) : null;
17285
17515
  break;
17286
17516
  }
17287
- if (d === dirname11(d)) break;
17517
+ if (d === dirname12(d)) break;
17288
17518
  }
17289
17519
  } catch {
17290
17520
  repo = null;
@@ -17302,14 +17532,14 @@ var init_git_remote = __esm({
17302
17532
  });
17303
17533
 
17304
17534
  // src/team/queue.ts
17305
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, appendFileSync as appendFileSync4, statSync as statSync5, mkdirSync as mkdirSync11 } from "node:fs";
17306
- import { dirname as dirname12 } from "node:path";
17535
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, appendFileSync as appendFileSync4, statSync as statSync6, mkdirSync as mkdirSync11 } from "node:fs";
17536
+ import { dirname as dirname13 } from "node:path";
17307
17537
  function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17308
- mkdirSync11(dirname12(queuePath), { recursive: true });
17538
+ mkdirSync11(dirname13(queuePath), { recursive: true });
17309
17539
  const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
17310
17540
  appendFileSync4(queuePath, JSON.stringify(entry) + "\n", "utf8");
17311
17541
  try {
17312
- const { size } = statSync5(queuePath);
17542
+ const { size } = statSync6(queuePath);
17313
17543
  if (size > MAX_SIZE_BYTES) {
17314
17544
  pruneOldest(queuePath);
17315
17545
  }
@@ -17319,7 +17549,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
17319
17549
  function dequeuePayloads(queuePath = QUEUE_PATH) {
17320
17550
  let lines;
17321
17551
  try {
17322
- lines = readFileSync16(queuePath, "utf8").trim().split("\n").filter(Boolean);
17552
+ lines = readFileSync17(queuePath, "utf8").trim().split("\n").filter(Boolean);
17323
17553
  } catch {
17324
17554
  return [];
17325
17555
  }
@@ -17340,7 +17570,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
17340
17570
  function pruneOldest(queuePath) {
17341
17571
  let lines;
17342
17572
  try {
17343
- lines = readFileSync16(queuePath, "utf8").trim().split("\n").filter(Boolean);
17573
+ lines = readFileSync17(queuePath, "utf8").trim().split("\n").filter(Boolean);
17344
17574
  } catch {
17345
17575
  return;
17346
17576
  }
@@ -17359,8 +17589,8 @@ var init_queue2 = __esm({
17359
17589
  });
17360
17590
 
17361
17591
  // src/usage/profile.ts
17362
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "node:fs";
17363
- import { dirname as dirname13 } from "node:path";
17592
+ import { existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
17593
+ import { dirname as dirname14 } from "node:path";
17364
17594
  function mapRateLimitTier(rateLimitTier) {
17365
17595
  switch (rateLimitTier) {
17366
17596
  case "default_claude_pro":
@@ -17400,9 +17630,9 @@ async function fetchProfile(nowMs = Date.now()) {
17400
17630
  };
17401
17631
  }
17402
17632
  function readCachedProfile(cachePath) {
17403
- if (!existsSync14(cachePath)) return null;
17633
+ if (!existsSync15(cachePath)) return null;
17404
17634
  try {
17405
- const raw = JSON.parse(readFileSync17(cachePath, "utf8"));
17635
+ const raw = JSON.parse(readFileSync18(cachePath, "utf8"));
17406
17636
  if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
17407
17637
  return raw;
17408
17638
  } catch {
@@ -17410,7 +17640,7 @@ function readCachedProfile(cachePath) {
17410
17640
  }
17411
17641
  }
17412
17642
  function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
17413
- mkdirSync12(dirname13(cachePath), { recursive: true });
17643
+ mkdirSync12(dirname14(cachePath), { recursive: true });
17414
17644
  writeFileSync11(
17415
17645
  cachePath,
17416
17646
  JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
@@ -17591,11 +17821,11 @@ var init_backfill = __esm({
17591
17821
  });
17592
17822
 
17593
17823
  // src/team/sync-log.ts
17594
- import { readFileSync as readFileSync18 } from "node:fs";
17824
+ import { readFileSync as readFileSync19 } from "node:fs";
17595
17825
  function readPendingSyncLog(watermark) {
17596
17826
  let raw;
17597
17827
  try {
17598
- raw = readFileSync18(cclensPath("daemon.log"), "utf8");
17828
+ raw = readFileSync19(cclensPath("daemon.log"), "utf8");
17599
17829
  } catch {
17600
17830
  return { lines: [] };
17601
17831
  }
@@ -17624,11 +17854,11 @@ var init_sync_log = __esm({
17624
17854
 
17625
17855
  // src/team/last-push.ts
17626
17856
  import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync5, mkdirSync as mkdirSync13 } from "node:fs";
17627
- import { join as join12 } from "node:path";
17857
+ import { join as join13 } from "node:path";
17628
17858
  function write(record, dir) {
17629
17859
  const d = dir ?? cclensHome();
17630
17860
  mkdirSync13(d, { recursive: true });
17631
- writeFileSync12(join12(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
17861
+ writeFileSync12(join13(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
17632
17862
  }
17633
17863
  function writeLastPushSuccess(payload, dir) {
17634
17864
  write({ pushedAt: (/* @__PURE__ */ new Date()).toISOString(), ok: true, payload }, dir);
@@ -17639,7 +17869,7 @@ function writeLastPushFailure(payload, error, dir) {
17639
17869
  function clearLastPush(dir) {
17640
17870
  const d = dir ?? cclensHome();
17641
17871
  try {
17642
- unlinkSync5(join12(d, LAST_PUSH_FILE));
17872
+ unlinkSync5(join13(d, LAST_PUSH_FILE));
17643
17873
  } catch {
17644
17874
  }
17645
17875
  }
@@ -17659,25 +17889,25 @@ __export(file_probe_exports, {
17659
17889
  probeArtifactSignals: () => probeArtifactSignals
17660
17890
  });
17661
17891
  import { createHash } from "node:crypto";
17662
- import { existsSync as existsSync15, readdirSync as readdirSync4, statSync as statSync6 } from "node:fs";
17663
- import { homedir as homedir5 } from "node:os";
17664
- import { join as join13, relative, resolve as resolve2, sep } from "node:path";
17892
+ import { existsSync as existsSync16, readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
17893
+ import { homedir as homedir6 } from "node:os";
17894
+ import { join as join14, relative, resolve as resolve3, sep } from "node:path";
17665
17895
  import { execFileSync as execFileSync3 } from "node:child_process";
17666
17896
  function pathHash(relPath) {
17667
17897
  return createHash("sha256").update(relPath.split(sep).join("/")).digest("hex").slice(0, 32);
17668
17898
  }
17669
17899
  function defaultScanRoots(extraRoots = []) {
17670
17900
  const roots = [];
17671
- const home = join13(homedir5(), ".claude");
17672
- if (existsSync15(home)) roots.push({ root: home, label: "user" });
17901
+ const home = join14(homedir6(), ".claude");
17902
+ if (existsSync16(home)) roots.push({ root: home, label: "user" });
17673
17903
  for (const e of extraRoots) {
17674
- const r = resolve2(e, ".claude");
17675
- if (existsSync15(r) && r !== home) roots.push({ root: r, label: "project" });
17904
+ const r = resolve3(e, ".claude");
17905
+ if (existsSync16(r) && r !== home) roots.push({ root: r, label: "project" });
17676
17906
  }
17677
17907
  return roots;
17678
17908
  }
17679
17909
  function listMarkdownFiles(dir) {
17680
- if (!existsSync15(dir)) return [];
17910
+ if (!existsSync16(dir)) return [];
17681
17911
  const out = [];
17682
17912
  let entries2;
17683
17913
  try {
@@ -17687,10 +17917,10 @@ function listMarkdownFiles(dir) {
17687
17917
  }
17688
17918
  for (const name of entries2) {
17689
17919
  if (name.startsWith(".")) continue;
17690
- const full = join13(dir, name);
17920
+ const full = join14(dir, name);
17691
17921
  let stat;
17692
17922
  try {
17693
- stat = statSync6(full);
17923
+ stat = statSync7(full);
17694
17924
  } catch {
17695
17925
  continue;
17696
17926
  }
@@ -17707,19 +17937,19 @@ function firstSeenDateOf(file) {
17707
17937
  const out = execFileSync3(
17708
17938
  "git",
17709
17939
  ["log", "--diff-filter=A", "--follow", "--format=%cs", "--", file],
17710
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname14(file) }
17940
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname15(file) }
17711
17941
  ).trim().split("\n").filter(Boolean);
17712
17942
  if (out.length > 0) return out[out.length - 1];
17713
17943
  } catch {
17714
17944
  }
17715
17945
  try {
17716
- const s = statSync6(file);
17946
+ const s = statSync7(file);
17717
17947
  return localDay(s.birthtime || s.mtime);
17718
17948
  } catch {
17719
17949
  return todayLocal();
17720
17950
  }
17721
17951
  }
17722
- function dirname14(p) {
17952
+ function dirname15(p) {
17723
17953
  const i = p.lastIndexOf(sep);
17724
17954
  return i < 0 ? "." : p.slice(0, i);
17725
17955
  }
@@ -17746,8 +17976,8 @@ function todayLocal() {
17746
17976
  function scanAuthored(roots, subdir, day2) {
17747
17977
  const out = [];
17748
17978
  for (const r of roots) {
17749
- const dir = join13(r.root, subdir);
17750
- if (!existsSync15(dir)) continue;
17979
+ const dir = join14(r.root, subdir);
17980
+ if (!existsSync16(dir)) continue;
17751
17981
  for (const f of listMarkdownFiles(dir)) {
17752
17982
  const firstSeen = firstSeenDateOf(f);
17753
17983
  if (firstSeen !== day2) continue;
@@ -17760,14 +17990,14 @@ function scanAuthored(roots, subdir, day2) {
17760
17990
  function scanEdited(roots, day2) {
17761
17991
  const out = [];
17762
17992
  for (const r of roots) {
17763
- const dir = join13(r.root, "skills");
17764
- if (!existsSync15(dir)) continue;
17993
+ const dir = join14(r.root, "skills");
17994
+ if (!existsSync16(dir)) continue;
17765
17995
  for (const f of listMarkdownFiles(dir)) {
17766
17996
  const firstSeen = firstSeenDateOf(f);
17767
17997
  if (firstSeen === day2) continue;
17768
17998
  let stat;
17769
17999
  try {
17770
- stat = statSync6(f);
18000
+ stat = statSync7(f);
17771
18001
  } catch {
17772
18002
  continue;
17773
18003
  }
@@ -17783,17 +18013,17 @@ function claudemdLineDelta(extraRoots, authorEmail, day2) {
17783
18013
  let delta = 0;
17784
18014
  const candidates = [];
17785
18015
  for (const e of extraRoots) {
17786
- const f = resolve2(e, "CLAUDE.md");
17787
- if (existsSync15(f)) candidates.push(f);
18016
+ const f = resolve3(e, "CLAUDE.md");
18017
+ if (existsSync16(f)) candidates.push(f);
17788
18018
  }
17789
- const homeClaudeMd = join13(homedir5(), "CLAUDE.md");
17790
- if (existsSync15(homeClaudeMd)) candidates.push(homeClaudeMd);
18019
+ const homeClaudeMd = join14(homedir6(), "CLAUDE.md");
18020
+ if (existsSync16(homeClaudeMd)) candidates.push(homeClaudeMd);
17791
18021
  for (const file of candidates) {
17792
18022
  try {
17793
18023
  const out = execFileSync3(
17794
18024
  "git",
17795
18025
  ["log", "--numstat", "--format=COMMIT %cs %ae", "--", file],
17796
- { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname14(file) }
18026
+ { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname15(file) }
17797
18027
  );
17798
18028
  let currentDate = "";
17799
18029
  let currentEmail = "";
@@ -17857,8 +18087,8 @@ async function dispatchCommand(command2, config, log) {
17857
18087
  }
17858
18088
  }
17859
18089
  async function runActivityBackfill(command2, config, log) {
17860
- const { listSessions: listSessions2, shouldSyncProject: shouldSyncProject2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
17861
- const { toLocalDay: toLocalDay4, projectRepoName: projectRepoName2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
18090
+ const { listSessions: listSessions2, resolveProjectIdentity: resolveProjectIdentity2, shouldSyncProject: shouldSyncProject2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
18091
+ const { toLocalDay: toLocalDay4, projectKey: projectKey2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
17862
18092
  const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
17863
18093
  const days = command2.params.days;
17864
18094
  const todayMs = Date.now();
@@ -17892,7 +18122,7 @@ async function runActivityBackfill(command2, config, log) {
17892
18122
  const richBlocks = buildRichBlocksForDay(rollup.day, daySessions, resolveRepo);
17893
18123
  let artifactSignals = null;
17894
18124
  try {
17895
- const cwdAllowed = shouldSyncProject2(projectRepoName2(process.cwd()), config.syncProjects);
18125
+ const cwdAllowed = shouldSyncProject2(projectKey2(resolveProjectIdentity2(process.cwd()).projectName), config.syncProjects);
17896
18126
  artifactSignals = probeArtifactSignals2({ day: rollup.day, extraRoots: cwdAllowed ? [process.cwd()] : [] });
17897
18127
  } catch {
17898
18128
  }
@@ -18044,7 +18274,7 @@ async function runTeamSync(log = noopLog2, configOverride, options = {}) {
18044
18274
  try {
18045
18275
  resetEnsuredSessions();
18046
18276
  const { listSessions: listSessions2, loadCalibrationCurve: loadCalibrationCurve2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
18047
- const { toLocalDay: toLocalDay4, projectRepoName: projectRepoName2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
18277
+ const { toLocalDay: toLocalDay4 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
18048
18278
  const today = toLocalDay4(Date.now());
18049
18279
  let patches = {};
18050
18280
  const persistConfig = (patch) => {
@@ -18231,7 +18461,7 @@ async function runTeamSync(log = noopLog2, configOverride, options = {}) {
18231
18461
  } : void 0;
18232
18462
  let artifactSignals = null;
18233
18463
  try {
18234
- const cwdAllowed = shouldSyncProject(projectRepoName2(process.cwd()), config.syncProjects);
18464
+ const cwdAllowed = shouldSyncProject(projectKey(resolveProjectIdentity(process.cwd()).projectName), config.syncProjects);
18235
18465
  artifactSignals = probeArtifactSignals2({ day: rollup.day, extraRoots: cwdAllowed ? [process.cwd()] : [] });
18236
18466
  } catch {
18237
18467
  }
@@ -18429,6 +18659,7 @@ var init_sync = __esm({
18429
18659
  init_last_push();
18430
18660
  init_commands();
18431
18661
  init_profile();
18662
+ init_dist();
18432
18663
  init_fs();
18433
18664
  inFlightCommands = /* @__PURE__ */ new Set();
18434
18665
  USAGE_LOG4 = cclensPath("usage.jsonl");
@@ -18659,11 +18890,11 @@ var logs_exports = {};
18659
18890
  __export(logs_exports, {
18660
18891
  teamLogs: () => teamLogs
18661
18892
  });
18662
- import { readFileSync as readFileSync19 } from "node:fs";
18893
+ import { readFileSync as readFileSync20 } from "node:fs";
18663
18894
  async function teamLogs() {
18664
18895
  const logPath = cclensPath("daemon.log");
18665
18896
  try {
18666
- const lines = readFileSync19(logPath, "utf8").trim().split("\n");
18897
+ const lines = readFileSync20(logPath, "utf8").trim().split("\n");
18667
18898
  const teamLines = lines.filter((l) => l.includes("[sync] ") || l.includes("team "));
18668
18899
  if (teamLines.length === 0) {
18669
18900
  console.log("No team-related log entries found.");
@@ -18791,8 +19022,8 @@ __export(runs_exports, {
18791
19022
  runs: () => runs
18792
19023
  });
18793
19024
  import { execSync as execSync2 } from "node:child_process";
18794
- import { existsSync as existsSync16, readFileSync as readFileSync20, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
18795
- import { join as join14 } from "node:path";
19025
+ import { existsSync as existsSync17, readFileSync as readFileSync21, readdirSync as readdirSync5, statSync as statSync8 } from "node:fs";
19026
+ import { join as join15 } from "node:path";
18796
19027
  async function runs(args2) {
18797
19028
  const json = args2.includes("--json");
18798
19029
  const watch = args2.includes("--watch");
@@ -18876,8 +19107,8 @@ function listActiveRuns() {
18876
19107
  return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
18877
19108
  }
18878
19109
  function readSpend(sinceMs) {
18879
- if (!existsSync16(SPEND_PATH)) return [];
18880
- const lines = readFileSync20(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
19110
+ if (!existsSync17(SPEND_PATH)) return [];
19111
+ const lines = readFileSync21(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
18881
19112
  const out = [];
18882
19113
  for (const line of lines) {
18883
19114
  try {
@@ -18998,23 +19229,23 @@ function ageLabel(ms) {
18998
19229
  return `${Math.floor(ms / 864e5)}d`;
18999
19230
  }
19000
19231
  function listTraceFiles() {
19001
- if (!existsSync16(RUNS_DIR2)) return [];
19232
+ if (!existsSync17(RUNS_DIR2)) return [];
19002
19233
  const entries2 = readdirSync5(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
19003
19234
  return entries2.map((f) => {
19004
- const path7 = join14(RUNS_DIR2, f);
19005
- const st = statSync7(path7);
19235
+ const path7 = join15(RUNS_DIR2, f);
19236
+ const st = statSync8(path7);
19006
19237
  return { runId: f.replace(/\.jsonl$/, ""), path: path7, mtimeMs: st.mtimeMs };
19007
19238
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
19008
19239
  }
19009
19240
  function resolveRunId(arg) {
19010
- if (!existsSync16(RUNS_DIR2)) return null;
19241
+ if (!existsSync17(RUNS_DIR2)) return null;
19011
19242
  if (arg === "latest") {
19012
19243
  const all2 = listTraceFiles();
19013
19244
  if (all2.length === 0) return null;
19014
19245
  return { runId: all2[0].runId, path: all2[0].path };
19015
19246
  }
19016
- const exact = join14(RUNS_DIR2, `${arg}.jsonl`);
19017
- if (existsSync16(exact)) return { runId: arg, path: exact };
19247
+ const exact = join15(RUNS_DIR2, `${arg}.jsonl`);
19248
+ if (existsSync17(exact)) return { runId: arg, path: exact };
19018
19249
  const all = listTraceFiles();
19019
19250
  const matches = all.filter((r) => r.runId.includes(arg));
19020
19251
  if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
@@ -19026,7 +19257,7 @@ function resolveRunId(arg) {
19026
19257
  return null;
19027
19258
  }
19028
19259
  function readTrace(path7) {
19029
- return readFileSync20(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
19260
+ return readFileSync21(path7, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
19030
19261
  try {
19031
19262
  return JSON.parse(l);
19032
19263
  } catch {
@@ -19038,7 +19269,7 @@ async function inspect(arg, follow, json) {
19038
19269
  const r = resolveRunId(arg);
19039
19270
  if (!r) {
19040
19271
  console.error(`run not found: ${arg}`);
19041
- if (existsSync16(RUNS_DIR2)) {
19272
+ if (existsSync17(RUNS_DIR2)) {
19042
19273
  const all = listTraceFiles().slice(0, 5);
19043
19274
  if (all.length > 0) {
19044
19275
  console.error(`
@@ -19058,13 +19289,13 @@ recent runs:`);
19058
19289
  const events = readTrace(r.path);
19059
19290
  printTrace(r.runId, events);
19060
19291
  if (!follow) return;
19061
- let lastSize = statSync7(r.path).size;
19292
+ let lastSize = statSync8(r.path).size;
19062
19293
  let lastIdx = events.length;
19063
19294
  console.log("\n \u27F6 following \xB7 ^C to quit\n");
19064
19295
  process.on("SIGINT", () => process.exit(0));
19065
19296
  while (true) {
19066
19297
  await new Promise((res) => setTimeout(res, 500));
19067
- const st = statSync7(r.path);
19298
+ const st = statSync8(r.path);
19068
19299
  if (st.size === lastSize) continue;
19069
19300
  lastSize = st.size;
19070
19301
  const all = readTrace(r.path);
@@ -19213,7 +19444,7 @@ async function main() {
19213
19444
  case "version":
19214
19445
  case "--version":
19215
19446
  case "-v":
19216
- console.log(`fleetlens ${"0.15.2"}`);
19447
+ console.log(`fleetlens ${"0.15.3"}`);
19217
19448
  break;
19218
19449
  case "help":
19219
19450
  case "--help":