fleetlens 0.11.2 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/apps/web/.next/BUILD_ID +1 -1
- package/app/apps/web/.next/app-path-routes-manifest.json +3 -0
- package/app/apps/web/.next/build-manifest.json +3 -3
- package/app/apps/web/.next/prerender-manifest.json +3 -3
- package/app/apps/web/.next/routes-manifest.json +22 -0
- package/app/apps/web/.next/server/app/_global-error.html +1 -1
- package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_not-found/page.js +2 -1
- package/app/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/api/ask/route.js +1 -1
- package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +2 -2
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js +2 -2
- package/app/apps/web/.next/server/app/api/digest/month/[yearMonth]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/month-index/route.js +1 -1
- package/app/apps/web/.next/server/app/api/digest/month-index/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +2 -2
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/week-index/route.js +1 -1
- package/app/apps/web/.next/server/app/api/digest/week-index/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/events/route.js +1 -1
- package/app/apps/web/.next/server/app/api/events/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/jobs/route.js +1 -1
- package/app/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/pdf/[key]/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route.js +10 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/runs/[runId]/route.js +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/route.js +1 -1
- package/app/apps/web/.next/server/app/api/runs/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/settings/route.js +1 -1
- package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/team-config/route.js +1 -1
- package/app/apps/web/.next/server/app/api/team-config/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/workflow-agent/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route.js +7 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/workflow-agent/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/changelog/page.js +2 -1
- package/app/apps/web/.next/server/app/changelog/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/day/[date]/page.js +2 -1
- package/app/apps/web/.next/server/app/day/[date]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/day/page.js +2 -1
- package/app/apps/web/.next/server/app/day/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/digest/[date]/page.js +2 -1
- package/app/apps/web/.next/server/app/digest/[date]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/digest/page.js +2 -1
- package/app/apps/web/.next/server/app/digest/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/insights/[key]/page.js +2 -1
- package/app/apps/web/.next/server/app/insights/[key]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/insights/page.js +2 -1
- package/app/apps/web/.next/server/app/insights/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/page.js +2 -1
- package/app/apps/web/.next/server/app/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/parallelism/page.js +2 -1
- package/app/apps/web/.next/server/app/parallelism/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/print/[key]/page/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/print/[key]/page/build-manifest.json +17 -0
- package/app/apps/web/.next/server/app/print/[key]/page/next-font-manifest.json +6 -0
- package/app/apps/web/.next/server/app/print/[key]/page/react-loadable-manifest.json +1 -0
- package/app/apps/web/.next/server/app/print/[key]/page/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/print/[key]/page.js +19 -0
- package/app/apps/web/.next/server/app/print/[key]/page.js.map +5 -0
- package/app/apps/web/.next/server/app/print/[key]/page.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/projects/[slug]/page.js +2 -1
- package/app/apps/web/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/projects/page.js +2 -1
- package/app/apps/web/.next/server/app/projects/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/runs/page.js +2 -1
- package/app/apps/web/.next/server/app/runs/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/sessions/[id]/page.js +2 -1
- package/app/apps/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/sessions/page.js +2 -1
- package/app/apps/web/.next/server/app/sessions/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/settings/page.js +2 -1
- package/app/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/team/page.js +2 -1
- package/app/apps/web/.next/server/app/team/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/usage/page.js +2 -1
- package/app/apps/web/.next/server/app/usage/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0455vu3._.js +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0_8zh-i._.js → [root-of-the-server]__04j3tng._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0jprdks._.js → [root-of-the-server]__0cnh3k4._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0e.f-t.._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0kc9e1n._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0y5p73y._.js +3 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0ej_p3s._.js → [root-of-the-server]__132eosx._.js} +2 -2
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_pdf_[key]_route_actions_0intcw9.js +3 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_workflow-agent_route_actions_0gxw9tv.js +3 -0
- package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +1 -1
- package/app/apps/web/.next/server/chunks/packages_parser_dist_06d9se1._.js +3 -0
- package/app/apps/web/.next/server/chunks/packages_parser_dist_10ihc3~._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04eq6z2._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__04il6m2._.js +11 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0exckd4._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0n-ax-5._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0o03ymy._.js +2 -2
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0rvzdnx._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0z7mg0b._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0~.f_3z._.js +12 -0
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__136-0me._.js +8 -0
- package/app/apps/web/.next/server/chunks/ssr/_0cgg5zi._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0jw2sm7._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/_0kajk31._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0w.cv64._.js +8 -0
- package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_0.mu7c7._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web__next-internal_server_app_print_[key]_page_actions_0_ygul-.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_01d-iwx._.js +6 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_week-digest_tsx_0c9ha31._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0k0tl52._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_07orc4m.js +4 -0
- package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_12.endt._.js +1 -1
- package/app/apps/web/.next/server/edge/chunks/[root-of-the-server]__0.sx~id._.js +11 -0
- package/app/apps/web/.next/server/edge/chunks/node_modules_next_dist_esm_build_templates_edge-wrapper_0p1t1z8.js +3 -0
- package/app/apps/web/.next/server/edge/chunks/turbopack-node_modules_next_dist_esm_build_templates_edge-wrapper_0mw-sqe.js +3 -0
- package/app/apps/web/.next/server/functions-config-manifest.json +4 -1
- package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/app/apps/web/.next/server/middleware-manifest.json +30 -2
- package/app/apps/web/.next/server/pages/500.html +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/app/apps/web/.next/static/chunks/00xkqnvk4-d1-.js +10 -0
- package/app/apps/web/.next/static/chunks/03_7wmpodz36t.js +1 -0
- package/app/apps/web/.next/static/chunks/0716x58e1_2c5.js +1 -0
- package/app/apps/web/.next/static/chunks/0nnjldasalwdu.js +4 -0
- package/app/apps/web/.next/static/chunks/0okg13phslr1..js +4 -0
- package/app/apps/web/.next/static/chunks/0vf-3rauafbek.js +6 -0
- package/app/apps/web/.next/static/chunks/0vl27-vjob2_9.js +6 -0
- package/app/apps/web/.next/static/chunks/0yo458-7577lr.js +1 -0
- package/app/apps/web/.next/static/chunks/14bjditmmrn7l.js +1 -0
- package/app/apps/web/.next/static/rrY-ephAArv8tjJOXD622/_clientMiddlewareManifest.js +6 -0
- package/app/apps/web/app/api/events/route.ts +50 -2
- package/app/apps/web/app/api/pdf/[key]/route.ts +199 -0
- package/app/apps/web/app/api/workflow-agent/route.ts +27 -0
- package/app/apps/web/app/insights/[key]/page.tsx +4 -1
- package/app/apps/web/app/layout.tsx +23 -1
- package/app/apps/web/app/page.tsx +24 -1
- package/app/apps/web/app/print/[key]/page.tsx +91 -0
- package/app/apps/web/app/projects/[slug]/page.tsx +6 -7
- package/app/apps/web/app/projects/page.tsx +2 -3
- package/app/apps/web/app/sessions/[id]/session-view.tsx +1297 -19
- package/app/apps/web/app/sessions/sessions-grid.tsx +10 -1
- package/app/apps/web/components/dashboard-view.tsx +2 -1
- package/app/apps/web/components/export-pdf-button.tsx +76 -0
- package/app/apps/web/components/month-digest-view.tsx +10 -0
- package/app/apps/web/components/week-digest-view.tsx +10 -0
- package/app/apps/web/lib/changelog-data.generated.ts +1 -1
- package/app/apps/web/lib/entries-index.ts +5 -4
- package/app/apps/web/lib/find-chrome.ts +71 -0
- package/app/apps/web/middleware.ts +22 -0
- package/app/apps/web/package.json +1 -1
- package/app/apps/web/tsconfig.tsbuildinfo +1 -1
- package/dist/daemon-worker.js +1716 -281
- package/dist/index.js +1617 -195
- package/package.json +1 -1
- package/app/apps/web/.next/server/chunks/packages_parser_dist_04rh1zd._.js +0 -3
- package/app/apps/web/.next/server/chunks/packages_parser_dist_0ndsxe6._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0_xpuh7._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0d~2~le._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0w52fbc._.js +0 -12
- package/app/apps/web/.next/server/chunks/ssr/_02s1n-x._.js +0 -8
- package/app/apps/web/.next/server/chunks/ssr/_0fjbf--._.js +0 -3
- package/app/apps/web/.next/server/chunks/ssr/apps_web_components_0ly1xes._.js +0 -6
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0af94gl._.js +0 -3
- package/app/apps/web/.next/static/chunks/0.3mqbj24kwtc.js +0 -6
- package/app/apps/web/.next/static/chunks/0byz8fqw.exef.js +0 -1
- package/app/apps/web/.next/static/chunks/0l3ck.awv~4t7.js +0 -1
- package/app/apps/web/.next/static/chunks/0lxuac2v0_gdl.js +0 -6
- package/app/apps/web/.next/static/chunks/0m62vx92~0_0d.js +0 -1
- package/app/apps/web/.next/static/chunks/0rtba0saz74e1.js +0 -10
- package/app/apps/web/.next/static/chunks/0s4eyofh28l~u.js +0 -1
- package/app/apps/web/.next/static/chunks/0uev~g~qvbjv9.js +0 -4
- package/app/apps/web/.next/static/m6ibRSdAu8jD10VBA2OFH/_clientMiddlewareManifest.js +0 -1
- /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → rrY-ephAArv8tjJOXD622}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → rrY-ephAArv8tjJOXD622}/_ssgManifest.js +0 -0
package/dist/daemon-worker.js
CHANGED
|
@@ -75,6 +75,16 @@ function findConductorWorkspace(projectName) {
|
|
|
75
75
|
const canonicalEndIdx = m.index + m[0].length - workspaceName.length - 1 - trailingSlash;
|
|
76
76
|
return { canonicalEndIdx, workspaceName };
|
|
77
77
|
}
|
|
78
|
+
function findSupersetWorkspace(projectName) {
|
|
79
|
+
const idx = projectName.indexOf(SUPERSET_MARKER);
|
|
80
|
+
if (idx < 0)
|
|
81
|
+
return null;
|
|
82
|
+
const segs = projectName.slice(idx + SUPERSET_MARKER.length).split("/").filter(Boolean);
|
|
83
|
+
if (segs.length === 0)
|
|
84
|
+
return null;
|
|
85
|
+
const workspaceName = UUID_SEG_RE.test(segs[0]) ? segs[1] ?? segs[0] : segs[0];
|
|
86
|
+
return { canonical: projectName.slice(0, idx) + SUPERSET_MARKER + workspaceName, workspaceName };
|
|
87
|
+
}
|
|
78
88
|
function canonicalProjectName(projectName) {
|
|
79
89
|
const normalized = projectName.replace(/\/{2,}/g, "/");
|
|
80
90
|
const wt = findWorktreeMarker(normalized);
|
|
@@ -83,6 +93,9 @@ function canonicalProjectName(projectName) {
|
|
|
83
93
|
const cd = findConductorWorkspace(normalized);
|
|
84
94
|
if (cd)
|
|
85
95
|
return normalized.slice(0, cd.canonicalEndIdx);
|
|
96
|
+
const ss = findSupersetWorkspace(normalized);
|
|
97
|
+
if (ss)
|
|
98
|
+
return ss.canonical;
|
|
86
99
|
return normalized;
|
|
87
100
|
}
|
|
88
101
|
function worktreeName(projectName) {
|
|
@@ -96,8 +109,16 @@ function worktreeName(projectName) {
|
|
|
96
109
|
const cd = findConductorWorkspace(normalized);
|
|
97
110
|
if (cd)
|
|
98
111
|
return cd.workspaceName;
|
|
112
|
+
const ss = findSupersetWorkspace(normalized);
|
|
113
|
+
if (ss)
|
|
114
|
+
return ss.workspaceName;
|
|
99
115
|
return null;
|
|
100
116
|
}
|
|
117
|
+
function projectRepoName(projectName) {
|
|
118
|
+
const canonical = canonicalProjectName(projectName);
|
|
119
|
+
const segs = canonical.replace(/\/+$/, "").split("/").filter(Boolean);
|
|
120
|
+
return segs[segs.length - 1] || canonical;
|
|
121
|
+
}
|
|
101
122
|
function makeDay(date) {
|
|
102
123
|
return {
|
|
103
124
|
date,
|
|
@@ -138,7 +159,19 @@ function dailyActivity(sessions) {
|
|
|
138
159
|
};
|
|
139
160
|
for (const s of sessions) {
|
|
140
161
|
const startDay = sessionDay(s);
|
|
141
|
-
if (
|
|
162
|
+
if (s.dailyBreakdown && s.dailyBreakdown.length > 0) {
|
|
163
|
+
for (const d of s.dailyBreakdown) {
|
|
164
|
+
const bucket = touchBucket(d.day);
|
|
165
|
+
bucket.toolCalls += d.toolCalls;
|
|
166
|
+
bucket.turns += d.turns;
|
|
167
|
+
bucket.tokens.input += d.tokens.input;
|
|
168
|
+
bucket.tokens.output += d.tokens.output;
|
|
169
|
+
bucket.tokens.cacheRead += d.tokens.cacheRead;
|
|
170
|
+
bucket.tokens.cacheWrite += d.tokens.cacheWrite;
|
|
171
|
+
}
|
|
172
|
+
if (startDay)
|
|
173
|
+
touchBucket(startDay).durationMs += s.durationMs ?? 0;
|
|
174
|
+
} else if (startDay) {
|
|
142
175
|
const bucket = touchBucket(startDay);
|
|
143
176
|
bucket.toolCalls += s.toolCallCount ?? 0;
|
|
144
177
|
bucket.turns += s.turnCount ?? 0;
|
|
@@ -148,31 +181,30 @@ function dailyActivity(sessions) {
|
|
|
148
181
|
bucket.tokens.cacheWrite += s.totalUsage.cacheWrite;
|
|
149
182
|
bucket.durationMs += s.durationMs ?? 0;
|
|
150
183
|
}
|
|
184
|
+
const presenceDays = /* @__PURE__ */ new Set();
|
|
151
185
|
const segments = s.activeSegments;
|
|
152
186
|
if (segments && segments.length > 0) {
|
|
153
|
-
const touchedDays = /* @__PURE__ */ new Set();
|
|
154
187
|
for (const seg of segments) {
|
|
155
188
|
let cur = seg.startMs;
|
|
156
189
|
while (cur < seg.endMs) {
|
|
157
190
|
const day = toLocalDay(cur);
|
|
158
|
-
|
|
191
|
+
presenceDays.add(day);
|
|
159
192
|
const d = new Date(cur);
|
|
160
193
|
d.setHours(24, 0, 0, 0);
|
|
161
194
|
const dayEndMs = Math.min(d.getTime(), seg.endMs);
|
|
162
|
-
|
|
163
|
-
bucket.airTimeMs += dayEndMs - cur;
|
|
195
|
+
touchBucket(day).airTimeMs += dayEndMs - cur;
|
|
164
196
|
cur = dayEndMs;
|
|
165
197
|
}
|
|
166
198
|
}
|
|
167
|
-
for (const day of touchedDays) {
|
|
168
|
-
const bucket = touchBucket(day);
|
|
169
|
-
bucket.sessions++;
|
|
170
|
-
}
|
|
171
199
|
} else if (startDay) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
bucket.airTimeMs += s.airTimeMs ?? 0;
|
|
200
|
+
presenceDays.add(startDay);
|
|
201
|
+
touchBucket(startDay).airTimeMs += s.airTimeMs ?? 0;
|
|
175
202
|
}
|
|
203
|
+
if (s.dailyBreakdown)
|
|
204
|
+
for (const d of s.dailyBreakdown)
|
|
205
|
+
presenceDays.add(d.day);
|
|
206
|
+
for (const day of presenceDays)
|
|
207
|
+
touchBucket(day).sessions++;
|
|
176
208
|
}
|
|
177
209
|
const range = minDay && maxDay ? daysBetween(minDay, maxDay) : [];
|
|
178
210
|
const out = [];
|
|
@@ -517,13 +549,13 @@ function summarizeBursts(bursts) {
|
|
|
517
549
|
function groupByProject(sessions) {
|
|
518
550
|
const map = /* @__PURE__ */ new Map();
|
|
519
551
|
for (const s of sessions) {
|
|
520
|
-
const
|
|
521
|
-
const key =
|
|
552
|
+
const repo = projectRepoName(s.projectName);
|
|
553
|
+
const key = repo;
|
|
522
554
|
let cur = map.get(key);
|
|
523
555
|
if (!cur) {
|
|
524
556
|
cur = {
|
|
525
|
-
projectDir:
|
|
526
|
-
projectName:
|
|
557
|
+
projectDir: repo,
|
|
558
|
+
projectName: repo,
|
|
527
559
|
sessions: [],
|
|
528
560
|
rawProjectDirs: [],
|
|
529
561
|
worktreeCount: 0,
|
|
@@ -565,7 +597,7 @@ function groupByProject(sessions) {
|
|
|
565
597
|
}
|
|
566
598
|
return Array.from(map.values()).sort((a, b) => (b.lastActiveMs ?? 0) - (a.lastActiveMs ?? 0));
|
|
567
599
|
}
|
|
568
|
-
var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
|
|
600
|
+
var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, SUPERSET_MARKER, UUID_SEG_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
|
|
569
601
|
var init_analytics = __esm({
|
|
570
602
|
"../parser/dist/analytics.js"() {
|
|
571
603
|
"use strict";
|
|
@@ -576,6 +608,8 @@ var init_analytics = __esm({
|
|
|
576
608
|
"/claude/worktrees/"
|
|
577
609
|
];
|
|
578
610
|
CONDUCTOR_RE = /\/conductor\/workspaces\/[^/]+\/([^/]+)(?:\/|$)/;
|
|
611
|
+
SUPERSET_MARKER = "/.superset/worktrees/";
|
|
612
|
+
UUID_SEG_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
579
613
|
PR_CREATE_RE = /gh\s+pr\s+create\b/i;
|
|
580
614
|
PR_NUMBER_RE = /#(\d+)/;
|
|
581
615
|
TITLE_FLAG_RE = /--title\s+["']([^"']+)["']/;
|
|
@@ -589,7 +623,7 @@ function getAgentMetadata(kind) {
|
|
|
589
623
|
function isAgentKind(s) {
|
|
590
624
|
return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
|
|
591
625
|
}
|
|
592
|
-
var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
|
|
626
|
+
var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
|
|
593
627
|
var init_agent_metadata = __esm({
|
|
594
628
|
"../parser/dist/agent-metadata.js"() {
|
|
595
629
|
"use strict";
|
|
@@ -614,10 +648,26 @@ var init_agent_metadata = __esm({
|
|
|
614
648
|
accentColor: "rgb(124, 92, 246)",
|
|
615
649
|
iconChar: "\u273A"
|
|
616
650
|
};
|
|
651
|
+
ANTIGRAVITY_METADATA = {
|
|
652
|
+
kind: "antigravity",
|
|
653
|
+
displayName: "Antigravity",
|
|
654
|
+
shortLabel: "Agy",
|
|
655
|
+
accentColor: "rgb(236, 72, 153)",
|
|
656
|
+
iconChar: "\u23C3"
|
|
657
|
+
};
|
|
658
|
+
COWORK_METADATA = {
|
|
659
|
+
kind: "cowork",
|
|
660
|
+
displayName: "Cowork",
|
|
661
|
+
shortLabel: "Cowork",
|
|
662
|
+
accentColor: "rgb(217, 119, 87)",
|
|
663
|
+
iconChar: "\u2318"
|
|
664
|
+
};
|
|
617
665
|
agentMetadata = [
|
|
618
666
|
CLAUDE_CODE_METADATA,
|
|
619
667
|
CODEX_METADATA,
|
|
620
|
-
GEMINI_METADATA
|
|
668
|
+
GEMINI_METADATA,
|
|
669
|
+
ANTIGRAVITY_METADATA,
|
|
670
|
+
COWORK_METADATA
|
|
621
671
|
];
|
|
622
672
|
KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
|
|
623
673
|
}
|
|
@@ -1199,9 +1249,31 @@ function parseTranscript(rawLines) {
|
|
|
1199
1249
|
let linesAdded = 0;
|
|
1200
1250
|
let linesRemoved = 0;
|
|
1201
1251
|
const filesEdited = /* @__PURE__ */ new Set();
|
|
1252
|
+
const perDay = /* @__PURE__ */ new Map();
|
|
1253
|
+
const fallbackDay = startMs !== void 0 ? toLocalDay(startMs) : void 0;
|
|
1254
|
+
const dayBucket = (ts) => {
|
|
1255
|
+
let day;
|
|
1256
|
+
if (ts) {
|
|
1257
|
+
const ms = Date.parse(ts);
|
|
1258
|
+
if (!Number.isNaN(ms))
|
|
1259
|
+
day = toLocalDay(ms);
|
|
1260
|
+
}
|
|
1261
|
+
day = day ?? fallbackDay;
|
|
1262
|
+
if (!day)
|
|
1263
|
+
return void 0;
|
|
1264
|
+
let b = perDay.get(day);
|
|
1265
|
+
if (!b) {
|
|
1266
|
+
b = { toolCalls: 0, turns: 0, tokens: { ...BLANK_USAGE2 } };
|
|
1267
|
+
perDay.set(day, b);
|
|
1268
|
+
}
|
|
1269
|
+
return b;
|
|
1270
|
+
};
|
|
1202
1271
|
for (const e of events) {
|
|
1203
1272
|
if (e.role === "tool-call") {
|
|
1204
1273
|
toolCallCount++;
|
|
1274
|
+
const tcDay = dayBucket(e.timestamp);
|
|
1275
|
+
if (tcDay)
|
|
1276
|
+
tcDay.toolCalls++;
|
|
1205
1277
|
const toolBlock = e.blocks.find((b) => b && b.type === "tool_use");
|
|
1206
1278
|
if (toolBlock) {
|
|
1207
1279
|
const input = toolBlock.input ?? {};
|
|
@@ -1238,6 +1310,9 @@ function parseTranscript(rawLines) {
|
|
|
1238
1310
|
firstUserPreview = e.teammateMessage ? e.teammateMessage.body : e.preview;
|
|
1239
1311
|
}
|
|
1240
1312
|
turnCount++;
|
|
1313
|
+
const turnDay = dayBucket(e.timestamp);
|
|
1314
|
+
if (turnDay)
|
|
1315
|
+
turnDay.turns++;
|
|
1241
1316
|
lastUserPreview = e.preview;
|
|
1242
1317
|
}
|
|
1243
1318
|
}
|
|
@@ -1279,6 +1354,14 @@ function parseTranscript(rawLines) {
|
|
|
1279
1354
|
totalUsage.output += u.output;
|
|
1280
1355
|
totalUsage.cacheRead += u.cacheRead;
|
|
1281
1356
|
totalUsage.cacheWrite += u.cacheWrite;
|
|
1357
|
+
const ts = typeof o.timestamp === "string" ? o.timestamp : void 0;
|
|
1358
|
+
const b = dayBucket(ts);
|
|
1359
|
+
if (b) {
|
|
1360
|
+
b.tokens.input += u.input;
|
|
1361
|
+
b.tokens.output += u.output;
|
|
1362
|
+
b.tokens.cacheRead += u.cacheRead;
|
|
1363
|
+
b.tokens.cacheWrite += u.cacheWrite;
|
|
1364
|
+
}
|
|
1282
1365
|
}
|
|
1283
1366
|
}
|
|
1284
1367
|
}
|
|
@@ -1302,6 +1385,7 @@ function parseTranscript(rawLines) {
|
|
|
1302
1385
|
lastAgentPreview,
|
|
1303
1386
|
toolCallCount,
|
|
1304
1387
|
turnCount,
|
|
1388
|
+
dailyBreakdown: Array.from(perDay.entries()).map(([day, v]) => ({ day, toolCalls: v.toolCalls, turns: v.turns, tokens: v.tokens })).sort((a, b) => a.day.localeCompare(b.day)),
|
|
1305
1389
|
airTimeMs,
|
|
1306
1390
|
activeSegments,
|
|
1307
1391
|
linesAdded,
|
|
@@ -1320,6 +1404,7 @@ var init_parser = __esm({
|
|
|
1320
1404
|
"../parser/dist/parser.js"() {
|
|
1321
1405
|
"use strict";
|
|
1322
1406
|
init_user_input();
|
|
1407
|
+
init_analytics();
|
|
1323
1408
|
BLANK_USAGE2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
1324
1409
|
TEAMMATE_MSG_RE = /^\s*<teammate-message\s+teammate_id="([^"]+)"[^>]*>([\s\S]*?)<\/teammate-message>/;
|
|
1325
1410
|
}
|
|
@@ -1593,7 +1678,7 @@ async function loadCalibrationEvents(root = DEFAULT_ROOT) {
|
|
|
1593
1678
|
out.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
1594
1679
|
return out;
|
|
1595
1680
|
}
|
|
1596
|
-
function aggregateUsageFromLines(lines, seenKeys, usage) {
|
|
1681
|
+
function aggregateUsageFromLines(lines, seenKeys, usage, perDay, fallbackDay) {
|
|
1597
1682
|
for (const raw of lines) {
|
|
1598
1683
|
if (!raw || typeof raw !== "object")
|
|
1599
1684
|
continue;
|
|
@@ -1613,35 +1698,131 @@ function aggregateUsageFromLines(lines, seenKeys, usage) {
|
|
|
1613
1698
|
const u = m.usage;
|
|
1614
1699
|
if (u) {
|
|
1615
1700
|
const toNum = (v) => typeof v === "number" ? v : 0;
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1701
|
+
const inp = toNum(u.input_tokens);
|
|
1702
|
+
const out = toNum(u.output_tokens);
|
|
1703
|
+
const cr = toNum(u.cache_read_input_tokens);
|
|
1704
|
+
const cw = toNum(u.cache_creation_input_tokens);
|
|
1705
|
+
usage.input += inp;
|
|
1706
|
+
usage.output += out;
|
|
1707
|
+
usage.cacheRead += cr;
|
|
1708
|
+
usage.cacheWrite += cw;
|
|
1709
|
+
if (perDay) {
|
|
1710
|
+
let day;
|
|
1711
|
+
const ts = typeof r.timestamp === "string" ? r.timestamp : void 0;
|
|
1712
|
+
if (ts) {
|
|
1713
|
+
const ms = Date.parse(ts);
|
|
1714
|
+
if (!Number.isNaN(ms))
|
|
1715
|
+
day = toLocalDay(ms);
|
|
1716
|
+
}
|
|
1717
|
+
day = day ?? fallbackDay;
|
|
1718
|
+
if (day) {
|
|
1719
|
+
let d = perDay.get(day);
|
|
1720
|
+
if (!d) {
|
|
1721
|
+
d = { ...BLANK_USAGE3 };
|
|
1722
|
+
perDay.set(day, d);
|
|
1723
|
+
}
|
|
1724
|
+
d.input += inp;
|
|
1725
|
+
d.output += out;
|
|
1726
|
+
d.cacheRead += cr;
|
|
1727
|
+
d.cacheWrite += cw;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1620
1730
|
}
|
|
1621
1731
|
}
|
|
1622
1732
|
}
|
|
1623
|
-
async function computeSessionUsageWithSubagents(parentLines, projectDirPath, sessionId) {
|
|
1733
|
+
async function computeSessionUsageWithSubagents(parentLines, projectDirPath, sessionId, fallbackDay) {
|
|
1624
1734
|
const usage = { ...BLANK_USAGE3 };
|
|
1625
1735
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
1626
|
-
|
|
1736
|
+
const perDay = /* @__PURE__ */ new Map();
|
|
1737
|
+
aggregateUsageFromLines(parentLines, seenKeys, usage, perDay, fallbackDay);
|
|
1627
1738
|
const subagentsDir = path.join(projectDirPath, sessionId, "subagents");
|
|
1628
1739
|
let entries;
|
|
1629
1740
|
try {
|
|
1630
1741
|
entries = await fs.readdir(subagentsDir);
|
|
1631
1742
|
} catch {
|
|
1632
|
-
return usage;
|
|
1743
|
+
return { usage, perDay };
|
|
1633
1744
|
}
|
|
1634
1745
|
const jsonlFiles = entries.filter((f) => f.endsWith(".jsonl"));
|
|
1635
1746
|
if (jsonlFiles.length === 0)
|
|
1636
|
-
return usage;
|
|
1747
|
+
return { usage, perDay };
|
|
1637
1748
|
await Promise.all(jsonlFiles.map(async (f) => {
|
|
1638
1749
|
try {
|
|
1639
1750
|
const lines = await readJsonlFile(path.join(subagentsDir, f));
|
|
1640
|
-
aggregateUsageFromLines(lines, seenKeys, usage);
|
|
1751
|
+
aggregateUsageFromLines(lines, seenKeys, usage, perDay, fallbackDay);
|
|
1752
|
+
} catch {
|
|
1753
|
+
}
|
|
1754
|
+
}));
|
|
1755
|
+
return { usage, perDay };
|
|
1756
|
+
}
|
|
1757
|
+
function mergeDailyTokens(base, perDayTokens, totalUsage) {
|
|
1758
|
+
const counts = new Map((base ?? []).map((d) => [d.day, d]));
|
|
1759
|
+
const days = /* @__PURE__ */ new Set([...counts.keys(), ...perDayTokens.keys()]);
|
|
1760
|
+
const out = [...days].sort((a, b) => a.localeCompare(b)).map((day) => ({
|
|
1761
|
+
day,
|
|
1762
|
+
toolCalls: counts.get(day)?.toolCalls ?? 0,
|
|
1763
|
+
turns: counts.get(day)?.turns ?? 0,
|
|
1764
|
+
tokens: { ...perDayTokens.get(day) ?? BLANK_USAGE3 }
|
|
1765
|
+
}));
|
|
1766
|
+
if (out.length > 0) {
|
|
1767
|
+
const summed = out.reduce((a, r) => ({
|
|
1768
|
+
input: a.input + r.tokens.input,
|
|
1769
|
+
output: a.output + r.tokens.output,
|
|
1770
|
+
cacheRead: a.cacheRead + r.tokens.cacheRead,
|
|
1771
|
+
cacheWrite: a.cacheWrite + r.tokens.cacheWrite
|
|
1772
|
+
}), { ...BLANK_USAGE3 });
|
|
1773
|
+
const first = out[0].tokens;
|
|
1774
|
+
first.input += totalUsage.input - summed.input;
|
|
1775
|
+
first.output += totalUsage.output - summed.output;
|
|
1776
|
+
first.cacheRead += totalUsage.cacheRead - summed.cacheRead;
|
|
1777
|
+
first.cacheWrite += totalUsage.cacheWrite - summed.cacheWrite;
|
|
1778
|
+
}
|
|
1779
|
+
return out;
|
|
1780
|
+
}
|
|
1781
|
+
async function scanWorkflowAggregate(projectDirPath, sessionId) {
|
|
1782
|
+
const dir = path.join(projectDirPath, sessionId, "workflows");
|
|
1783
|
+
let entries;
|
|
1784
|
+
try {
|
|
1785
|
+
entries = await fs.readdir(dir);
|
|
1786
|
+
} catch {
|
|
1787
|
+
return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
|
|
1788
|
+
}
|
|
1789
|
+
const jsonFiles = entries.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
|
|
1790
|
+
if (jsonFiles.length === 0)
|
|
1791
|
+
return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
|
|
1792
|
+
let spawnedAgentCount = 0;
|
|
1793
|
+
const spans = [];
|
|
1794
|
+
const parsed = await Promise.all(jsonFiles.map(async (f) => {
|
|
1795
|
+
try {
|
|
1796
|
+
const j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
|
|
1797
|
+
if (typeof j.agentCount === "number")
|
|
1798
|
+
spawnedAgentCount += j.agentCount;
|
|
1799
|
+
if (typeof j.startTime === "number" && typeof j.durationMs === "number" && j.durationMs > 0) {
|
|
1800
|
+
spans.push({ startMs: j.startTime, endMs: j.startTime + j.durationMs });
|
|
1801
|
+
}
|
|
1802
|
+
return true;
|
|
1641
1803
|
} catch {
|
|
1804
|
+
return false;
|
|
1642
1805
|
}
|
|
1643
1806
|
}));
|
|
1644
|
-
return
|
|
1807
|
+
return { workflowCount: parsed.filter(Boolean).length, spawnedAgentCount, spans };
|
|
1808
|
+
}
|
|
1809
|
+
function foldWorkflowAgentTime(activeSegments, spans) {
|
|
1810
|
+
if (spans.length === 0)
|
|
1811
|
+
return {};
|
|
1812
|
+
const all = [...activeSegments ?? [], ...spans].filter((s) => s.endMs > s.startMs).sort((a, b) => a.startMs - b.startMs);
|
|
1813
|
+
if (all.length === 0)
|
|
1814
|
+
return {};
|
|
1815
|
+
const merged = [{ ...all[0] }];
|
|
1816
|
+
for (let i = 1; i < all.length; i++) {
|
|
1817
|
+
const cur = all[i];
|
|
1818
|
+
const last = merged[merged.length - 1];
|
|
1819
|
+
if (cur.startMs <= last.endMs)
|
|
1820
|
+
last.endMs = Math.max(last.endMs, cur.endMs);
|
|
1821
|
+
else
|
|
1822
|
+
merged.push({ ...cur });
|
|
1823
|
+
}
|
|
1824
|
+
const airTimeMs = merged.reduce((n, s) => n + (s.endMs - s.startMs), 0);
|
|
1825
|
+
return { activeSegments: merged, airTimeMs };
|
|
1645
1826
|
}
|
|
1646
1827
|
async function getCachedMeta(f) {
|
|
1647
1828
|
const cached = metaCache.get(f.fullPath);
|
|
@@ -1653,13 +1834,19 @@ async function getCachedMeta(f) {
|
|
|
1653
1834
|
const { meta } = parseTranscript(rawLines);
|
|
1654
1835
|
const sessionId = sessionIdFromFileName(f.fileName);
|
|
1655
1836
|
const projectDirPath = path.dirname(f.fullPath);
|
|
1656
|
-
meta.
|
|
1837
|
+
const fallbackDay = meta.firstTimestamp ? toLocalDay(Date.parse(meta.firstTimestamp)) : void 0;
|
|
1838
|
+
const { usage, perDay: perDayTokens } = await computeSessionUsageWithSubagents(rawLines, projectDirPath, sessionId, fallbackDay);
|
|
1839
|
+
meta.totalUsage = usage;
|
|
1840
|
+
meta.dailyBreakdown = mergeDailyTokens(meta.dailyBreakdown, perDayTokens, usage);
|
|
1841
|
+
const wf = await scanWorkflowAggregate(projectDirPath, sessionId);
|
|
1657
1842
|
const full = {
|
|
1658
1843
|
...meta,
|
|
1659
1844
|
id: sessionId,
|
|
1660
1845
|
filePath: f.fullPath,
|
|
1661
1846
|
projectDir: f.projectDir,
|
|
1662
|
-
projectName: meta.cwd ?? decodeProjectName(f.projectDir)
|
|
1847
|
+
projectName: meta.cwd ?? decodeProjectName(f.projectDir),
|
|
1848
|
+
...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
|
|
1849
|
+
...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
|
|
1663
1850
|
};
|
|
1664
1851
|
metaCache.set(f.fullPath, { meta: full, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
|
|
1665
1852
|
return full;
|
|
@@ -1675,13 +1862,17 @@ async function getCachedDetail(f) {
|
|
|
1675
1862
|
try {
|
|
1676
1863
|
const rawLines = await readJsonlFile(f.fullPath);
|
|
1677
1864
|
const { meta, events } = parseTranscript(rawLines);
|
|
1865
|
+
const sessionId = sessionIdFromFileName(f.fileName);
|
|
1866
|
+
const wf = await scanWorkflowAggregate(path.dirname(f.fullPath), sessionId);
|
|
1678
1867
|
const detail = {
|
|
1679
1868
|
...meta,
|
|
1680
|
-
id:
|
|
1869
|
+
id: sessionId,
|
|
1681
1870
|
filePath: f.fullPath,
|
|
1682
1871
|
projectDir: f.projectDir,
|
|
1683
1872
|
projectName: meta.cwd ?? decodeProjectName(f.projectDir),
|
|
1684
|
-
events
|
|
1873
|
+
events,
|
|
1874
|
+
...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
|
|
1875
|
+
...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
|
|
1685
1876
|
};
|
|
1686
1877
|
detailCache.set(f.fullPath, { detail, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
|
|
1687
1878
|
const metaOnly = { ...detail };
|
|
@@ -1713,8 +1904,18 @@ async function getSession(id, opts = {}) {
|
|
|
1713
1904
|
return detail;
|
|
1714
1905
|
const sessionStartMs = detail.firstTimestamp ? Date.parse(detail.firstTimestamp) : void 0;
|
|
1715
1906
|
const subagentsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "subagents");
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1907
|
+
const workflowsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "workflows");
|
|
1908
|
+
const [subagents, workflows] = await Promise.all([
|
|
1909
|
+
loadSubagents(subagentsDir, sessionStartMs, detail.events),
|
|
1910
|
+
loadWorkflows(workflowsDir, sessionStartMs, detail.events)
|
|
1911
|
+
]);
|
|
1912
|
+
const spawnedAgentCount = workflows.reduce((n, w) => n + w.agentCount, 0);
|
|
1913
|
+
return {
|
|
1914
|
+
...detail,
|
|
1915
|
+
subagents,
|
|
1916
|
+
workflows,
|
|
1917
|
+
...workflows.length > 0 ? { workflowCount: workflows.length, spawnedAgentCount } : {}
|
|
1918
|
+
};
|
|
1718
1919
|
}
|
|
1719
1920
|
function summarizeSubagentLines(lines) {
|
|
1720
1921
|
let startMs;
|
|
@@ -1904,6 +2105,248 @@ async function loadSubagents(dir, sessionStartMs, parentEvents) {
|
|
|
1904
2105
|
}));
|
|
1905
2106
|
return runs.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
|
|
1906
2107
|
}
|
|
2108
|
+
async function loadWorkflows(dir, sessionStartMs, parentEvents) {
|
|
2109
|
+
let entries;
|
|
2110
|
+
try {
|
|
2111
|
+
entries = await fs.readdir(dir);
|
|
2112
|
+
} catch {
|
|
2113
|
+
return [];
|
|
2114
|
+
}
|
|
2115
|
+
const jsonFiles = entries.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
|
|
2116
|
+
if (jsonFiles.length === 0)
|
|
2117
|
+
return [];
|
|
2118
|
+
const dispatches = [];
|
|
2119
|
+
for (const e of parentEvents) {
|
|
2120
|
+
if (e.role !== "tool-call" || e.toolName !== "Workflow")
|
|
2121
|
+
continue;
|
|
2122
|
+
const tsMs = e.timestamp ? Date.parse(e.timestamp) : NaN;
|
|
2123
|
+
if (Number.isNaN(tsMs))
|
|
2124
|
+
continue;
|
|
2125
|
+
for (const b of e.blocks) {
|
|
2126
|
+
if (b?.type !== "tool_use" || b.name !== "Workflow")
|
|
2127
|
+
continue;
|
|
2128
|
+
dispatches.push({ toolUseId: b.id, parentUuid: e.uuid ?? "", tsMs });
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
dispatches.sort((a, b) => a.tsMs - b.tsMs);
|
|
2132
|
+
const matchDispatch = (startMs) => {
|
|
2133
|
+
if (startMs === void 0 || dispatches.length === 0)
|
|
2134
|
+
return void 0;
|
|
2135
|
+
const TOLERANCE_MS = 6e4;
|
|
2136
|
+
let before;
|
|
2137
|
+
let beforeDelta = Infinity;
|
|
2138
|
+
let nearest;
|
|
2139
|
+
let nearestDelta = Infinity;
|
|
2140
|
+
for (const d of dispatches) {
|
|
2141
|
+
const delta = Math.abs(startMs - d.tsMs);
|
|
2142
|
+
if (delta > TOLERANCE_MS)
|
|
2143
|
+
continue;
|
|
2144
|
+
if (delta < nearestDelta) {
|
|
2145
|
+
nearest = d;
|
|
2146
|
+
nearestDelta = delta;
|
|
2147
|
+
}
|
|
2148
|
+
if (d.tsMs <= startMs && delta < beforeDelta) {
|
|
2149
|
+
before = d;
|
|
2150
|
+
beforeDelta = delta;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
return before ?? nearest;
|
|
2154
|
+
};
|
|
2155
|
+
const num2 = (v) => typeof v === "number" ? v : void 0;
|
|
2156
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
2157
|
+
const runs = await Promise.all(jsonFiles.map(async (f) => {
|
|
2158
|
+
let j;
|
|
2159
|
+
try {
|
|
2160
|
+
j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
|
|
2161
|
+
} catch {
|
|
2162
|
+
return null;
|
|
2163
|
+
}
|
|
2164
|
+
const runId = str(j.runId) ?? f.replace(/\.json$/, "");
|
|
2165
|
+
const startMs = num2(j.startTime);
|
|
2166
|
+
const durationMs = num2(j.durationMs);
|
|
2167
|
+
const endMs = startMs !== void 0 && durationMs !== void 0 ? startMs + durationMs : void 0;
|
|
2168
|
+
const startTOffsetMs = sessionStartMs !== void 0 && startMs !== void 0 ? Math.max(0, startMs - sessionStartMs) : void 0;
|
|
2169
|
+
const endTOffsetMs = sessionStartMs !== void 0 && endMs !== void 0 ? Math.max(0, endMs - sessionStartMs) : void 0;
|
|
2170
|
+
const phases = Array.isArray(j.phases) ? j.phases.filter((p) => !!p && typeof p === "object" && typeof p.title === "string").map((p) => ({ title: p.title, detail: str(p.detail) })) : [];
|
|
2171
|
+
const logs = Array.isArray(j.logs) ? j.logs.filter((l) => typeof l === "string") : [];
|
|
2172
|
+
const cap = (v, n) => {
|
|
2173
|
+
const s = str(v);
|
|
2174
|
+
return s === void 0 ? void 0 : s.length > n ? s.slice(0, n) + "\u2026" : s;
|
|
2175
|
+
};
|
|
2176
|
+
const progress = Array.isArray(j.workflowProgress) ? j.workflowProgress : [];
|
|
2177
|
+
const agents = progress.filter((e) => !!e && typeof e === "object" && e.type === "workflow_agent").map((e) => ({
|
|
2178
|
+
index: num2(e.index) ?? 0,
|
|
2179
|
+
label: str(e.label) ?? "(agent)",
|
|
2180
|
+
phaseIndex: num2(e.phaseIndex),
|
|
2181
|
+
phaseTitle: str(e.phaseTitle),
|
|
2182
|
+
agentId: str(e.agentId),
|
|
2183
|
+
model: str(e.model),
|
|
2184
|
+
state: str(e.state),
|
|
2185
|
+
startedAt: num2(e.startedAt),
|
|
2186
|
+
durationMs: num2(e.durationMs),
|
|
2187
|
+
tokens: num2(e.tokens),
|
|
2188
|
+
toolCalls: num2(e.toolCalls),
|
|
2189
|
+
lastToolSummary: cap(e.lastToolSummary, 200),
|
|
2190
|
+
promptPreview: cap(e.promptPreview, 600),
|
|
2191
|
+
resultPreview: cap(e.resultPreview, 600)
|
|
2192
|
+
})).sort((a, b) => a.index - b.index);
|
|
2193
|
+
const parent = matchDispatch(startMs);
|
|
2194
|
+
return {
|
|
2195
|
+
runId,
|
|
2196
|
+
name: str(j.workflowName) ?? runId,
|
|
2197
|
+
description: str(j.summary),
|
|
2198
|
+
status: str(j.status) ?? "unknown",
|
|
2199
|
+
agentCount: num2(j.agentCount) ?? 0,
|
|
2200
|
+
toolCallCount: num2(j.totalToolCalls) ?? 0,
|
|
2201
|
+
totalTokens: num2(j.totalTokens) ?? 0,
|
|
2202
|
+
durationMs,
|
|
2203
|
+
startMs,
|
|
2204
|
+
endMs,
|
|
2205
|
+
startTOffsetMs,
|
|
2206
|
+
endTOffsetMs,
|
|
2207
|
+
model: str(j.defaultModel),
|
|
2208
|
+
phases,
|
|
2209
|
+
logs,
|
|
2210
|
+
agents,
|
|
2211
|
+
parentToolUseId: parent?.toolUseId,
|
|
2212
|
+
parentUuid: parent?.parentUuid
|
|
2213
|
+
};
|
|
2214
|
+
}));
|
|
2215
|
+
return runs.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
|
|
2216
|
+
}
|
|
2217
|
+
function salientToolInput(input) {
|
|
2218
|
+
if (!input || typeof input !== "object")
|
|
2219
|
+
return "";
|
|
2220
|
+
const o = input;
|
|
2221
|
+
const pick = (k) => typeof o[k] === "string" ? o[k] : void 0;
|
|
2222
|
+
return pick("command") ?? pick("file_path") ?? pick("path") ?? pick("pattern") ?? pick("url") ?? pick("description") ?? pick("query") ?? pick("prompt") ?? pick("old_string") ?? JSON.stringify(o);
|
|
2223
|
+
}
|
|
2224
|
+
async function loadWorkflowAgentDetail(sessionId, runId, agentId, opts = {}) {
|
|
2225
|
+
const { root = DEFAULT_ROOT } = opts;
|
|
2226
|
+
if (!/^[\w.-]+$/.test(runId) || !/^[\w.-]+$/.test(agentId))
|
|
2227
|
+
return null;
|
|
2228
|
+
const files = await walkJsonlFiles(root);
|
|
2229
|
+
const hit = files.find((f) => sessionIdFromFileName(f.fileName) === sessionId);
|
|
2230
|
+
if (!hit)
|
|
2231
|
+
return null;
|
|
2232
|
+
const file = path.join(path.dirname(hit.fullPath), sessionId, "subagents", "workflows", runId, `agent-${agentId}.jsonl`);
|
|
2233
|
+
let lines;
|
|
2234
|
+
try {
|
|
2235
|
+
lines = await readJsonlFile(file);
|
|
2236
|
+
} catch {
|
|
2237
|
+
return null;
|
|
2238
|
+
}
|
|
2239
|
+
const errored = /* @__PURE__ */ new Set();
|
|
2240
|
+
for (const raw of lines) {
|
|
2241
|
+
if (!raw || typeof raw !== "object")
|
|
2242
|
+
continue;
|
|
2243
|
+
const content = raw.message?.content;
|
|
2244
|
+
if (!Array.isArray(content))
|
|
2245
|
+
continue;
|
|
2246
|
+
for (const b of content) {
|
|
2247
|
+
if (b && typeof b === "object" && b.type === "tool_result" && b.is_error === true && typeof b.tool_use_id === "string") {
|
|
2248
|
+
errored.add(b.tool_use_id);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
const steps = [];
|
|
2253
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
2254
|
+
const totalUsage = { ...BLANK_USAGE3 };
|
|
2255
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2256
|
+
let prompt;
|
|
2257
|
+
let finalText;
|
|
2258
|
+
let model;
|
|
2259
|
+
let assistantMessageCount = 0;
|
|
2260
|
+
let eventCount = 0;
|
|
2261
|
+
let startMs;
|
|
2262
|
+
let endMs;
|
|
2263
|
+
for (const raw of lines) {
|
|
2264
|
+
if (!raw || typeof raw !== "object")
|
|
2265
|
+
continue;
|
|
2266
|
+
const r = raw;
|
|
2267
|
+
eventCount++;
|
|
2268
|
+
const ts = typeof r.timestamp === "string" ? Date.parse(r.timestamp) : NaN;
|
|
2269
|
+
if (!Number.isNaN(ts)) {
|
|
2270
|
+
if (startMs === void 0 || ts < startMs)
|
|
2271
|
+
startMs = ts;
|
|
2272
|
+
if (endMs === void 0 || ts > endMs)
|
|
2273
|
+
endMs = ts;
|
|
2274
|
+
}
|
|
2275
|
+
if (prompt === void 0 && r.type === "user" && (r.parentUuid === null || r.parentUuid === void 0)) {
|
|
2276
|
+
const c = r.message?.content;
|
|
2277
|
+
if (typeof c === "string")
|
|
2278
|
+
prompt = c;
|
|
2279
|
+
else if (Array.isArray(c)) {
|
|
2280
|
+
const t = c.find((b) => b && typeof b === "object" && b.type === "text");
|
|
2281
|
+
if (t?.text)
|
|
2282
|
+
prompt = t.text;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
if (r.type !== "assistant")
|
|
2286
|
+
continue;
|
|
2287
|
+
const m = r.message;
|
|
2288
|
+
if (!m)
|
|
2289
|
+
continue;
|
|
2290
|
+
if (!model && typeof m.model === "string")
|
|
2291
|
+
model = m.model;
|
|
2292
|
+
const mid = typeof m.id === "string" ? m.id : void 0;
|
|
2293
|
+
const rid = typeof r.requestId === "string" ? r.requestId : void 0;
|
|
2294
|
+
const key = mid != null && rid != null ? `${mid}:${rid}` : void 0;
|
|
2295
|
+
const fresh = key ? !seen.has(key) : true;
|
|
2296
|
+
if (key && fresh)
|
|
2297
|
+
seen.add(key);
|
|
2298
|
+
if (fresh) {
|
|
2299
|
+
assistantMessageCount++;
|
|
2300
|
+
const u = m.usage;
|
|
2301
|
+
if (u) {
|
|
2302
|
+
const n = (v) => typeof v === "number" ? v : 0;
|
|
2303
|
+
totalUsage.input += n(u.input_tokens);
|
|
2304
|
+
totalUsage.output += n(u.output_tokens);
|
|
2305
|
+
totalUsage.cacheRead += n(u.cache_read_input_tokens);
|
|
2306
|
+
totalUsage.cacheWrite += n(u.cache_creation_input_tokens);
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
const content = m.content;
|
|
2310
|
+
if (!Array.isArray(content))
|
|
2311
|
+
continue;
|
|
2312
|
+
for (const b of content) {
|
|
2313
|
+
if (!b || typeof b !== "object")
|
|
2314
|
+
continue;
|
|
2315
|
+
if (b.type === "text" && typeof b.text === "string") {
|
|
2316
|
+
finalText = b.text;
|
|
2317
|
+
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
2318
|
+
toolCounts.set(b.name, (toolCounts.get(b.name) ?? 0) + 1);
|
|
2319
|
+
if (steps.length < 2e3) {
|
|
2320
|
+
const salient = salientToolInput(b.input);
|
|
2321
|
+
const preview = salient.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
2322
|
+
const full = salient.length > 4e3 ? salient.slice(0, 4e3) + "\u2026" : salient;
|
|
2323
|
+
steps.push({
|
|
2324
|
+
index: steps.length + 1,
|
|
2325
|
+
tool: b.name,
|
|
2326
|
+
preview,
|
|
2327
|
+
// Only carry `full` when it adds something over the one-line preview.
|
|
2328
|
+
full: full.length > preview.length || full.includes("\n") ? full : void 0,
|
|
2329
|
+
isError: typeof b.id === "string" && errored.has(b.id)
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
const toolCalls = Array.from(toolCounts.entries()).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
|
|
2336
|
+
return {
|
|
2337
|
+
agentId,
|
|
2338
|
+
prompt,
|
|
2339
|
+
finalText,
|
|
2340
|
+
steps,
|
|
2341
|
+
toolCalls,
|
|
2342
|
+
toolCallCount: steps.length,
|
|
2343
|
+
assistantMessageCount,
|
|
2344
|
+
eventCount,
|
|
2345
|
+
totalUsage,
|
|
2346
|
+
model,
|
|
2347
|
+
durationMs: startMs !== void 0 && endMs !== void 0 ? endMs - startMs : void 0
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
1907
2350
|
async function listProjects(root = DEFAULT_ROOT) {
|
|
1908
2351
|
const files = await walkJsonlFiles(root);
|
|
1909
2352
|
const byRawDir = /* @__PURE__ */ new Map();
|
|
@@ -1925,10 +2368,10 @@ async function listProjects(root = DEFAULT_ROOT) {
|
|
|
1925
2368
|
const canonicalMap = /* @__PURE__ */ new Map();
|
|
1926
2369
|
for (const [rawDir, { count, lastActiveMs }] of byRawDir) {
|
|
1927
2370
|
const cwdOrDecoded = cwdForProject(rawDir) ?? decodeProjectName(rawDir);
|
|
1928
|
-
const
|
|
2371
|
+
const repo = projectRepoName(cwdOrDecoded);
|
|
1929
2372
|
const wt = worktreeName(cwdOrDecoded);
|
|
1930
|
-
const agg = canonicalMap.get(
|
|
1931
|
-
canonicalName:
|
|
2373
|
+
const agg = canonicalMap.get(repo) ?? {
|
|
2374
|
+
canonicalName: repo,
|
|
1932
2375
|
count: 0,
|
|
1933
2376
|
lastActiveMs: 0,
|
|
1934
2377
|
worktreeBranches: /* @__PURE__ */ new Set()
|
|
@@ -1938,7 +2381,7 @@ async function listProjects(root = DEFAULT_ROOT) {
|
|
|
1938
2381
|
agg.lastActiveMs = lastActiveMs;
|
|
1939
2382
|
if (wt)
|
|
1940
2383
|
agg.worktreeBranches.add(wt);
|
|
1941
|
-
canonicalMap.set(
|
|
2384
|
+
canonicalMap.set(repo, agg);
|
|
1942
2385
|
}
|
|
1943
2386
|
return Array.from(canonicalMap.values()).map((a) => ({
|
|
1944
2387
|
projectDir: a.canonicalName,
|
|
@@ -2838,76 +3281,705 @@ async function parseSession(file) {
|
|
|
2838
3281
|
prevMs = ms;
|
|
2839
3282
|
}
|
|
2840
3283
|
}
|
|
2841
|
-
const activeSegments = computeActiveSegments3(tsMs);
|
|
2842
|
-
const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
|
|
2843
|
-
const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
|
|
2844
|
-
const sessionId = metaRec.sessionId ?? file.filenameId;
|
|
2845
|
-
const projectName = cwd ? canonicalProjectName(cwd) : file.slug;
|
|
2846
|
-
const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.slug;
|
|
3284
|
+
const activeSegments = computeActiveSegments3(tsMs);
|
|
3285
|
+
const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
|
|
3286
|
+
const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
|
|
3287
|
+
const sessionId = metaRec.sessionId ?? file.filenameId;
|
|
3288
|
+
const projectName = cwd ? canonicalProjectName(cwd) : file.slug;
|
|
3289
|
+
const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.slug;
|
|
3290
|
+
const meta = {
|
|
3291
|
+
agent: "gemini",
|
|
3292
|
+
id: sessionId,
|
|
3293
|
+
filePath: file.filePath,
|
|
3294
|
+
projectName,
|
|
3295
|
+
projectDir,
|
|
3296
|
+
sessionId,
|
|
3297
|
+
firstTimestamp,
|
|
3298
|
+
lastTimestamp,
|
|
3299
|
+
durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
|
|
3300
|
+
eventCount: events.length,
|
|
3301
|
+
model,
|
|
3302
|
+
cwd,
|
|
3303
|
+
totalUsage,
|
|
3304
|
+
status: "idle",
|
|
3305
|
+
firstUserPreview,
|
|
3306
|
+
lastUserPreview,
|
|
3307
|
+
lastAgentPreview,
|
|
3308
|
+
toolCallCount,
|
|
3309
|
+
turnCount,
|
|
3310
|
+
airTimeMs,
|
|
3311
|
+
activeSegments
|
|
3312
|
+
};
|
|
3313
|
+
return { meta, events };
|
|
3314
|
+
}
|
|
3315
|
+
function computeActiveSegments3(tsMs) {
|
|
3316
|
+
if (tsMs.length === 0)
|
|
3317
|
+
return [];
|
|
3318
|
+
const sorted = [...tsMs].sort((a, b) => a - b);
|
|
3319
|
+
const out = [];
|
|
3320
|
+
let segStart = sorted[0];
|
|
3321
|
+
let segEnd = sorted[0];
|
|
3322
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
3323
|
+
if (sorted[i] - segEnd > IDLE_GAP_MS2) {
|
|
3324
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3325
|
+
segStart = sorted[i];
|
|
3326
|
+
}
|
|
3327
|
+
segEnd = sorted[i];
|
|
3328
|
+
}
|
|
3329
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3330
|
+
return out;
|
|
3331
|
+
}
|
|
3332
|
+
function clearGeminiCaches() {
|
|
3333
|
+
metaCache3.clear();
|
|
3334
|
+
detailCache3.clear();
|
|
3335
|
+
projectsCache = null;
|
|
3336
|
+
}
|
|
3337
|
+
async function listGeminiSessions(opts = {}) {
|
|
3338
|
+
const root = opts.root ?? DEFAULT_GEMINI_ROOT;
|
|
3339
|
+
const files = await listSessionFiles(root);
|
|
3340
|
+
const out = [];
|
|
3341
|
+
for (const file of files) {
|
|
3342
|
+
const cached = metaCache3.get(file.filePath);
|
|
3343
|
+
if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
|
|
3344
|
+
out.push(cached.meta);
|
|
3345
|
+
continue;
|
|
3346
|
+
}
|
|
3347
|
+
try {
|
|
3348
|
+
const { meta } = await parseSession(file);
|
|
3349
|
+
metaCache3.set(file.filePath, {
|
|
3350
|
+
meta,
|
|
3351
|
+
mtimeMs: file.mtimeMs,
|
|
3352
|
+
sizeBytes: file.sizeBytes
|
|
3353
|
+
});
|
|
3354
|
+
out.push(meta);
|
|
3355
|
+
} catch {
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
|
|
3359
|
+
if (opts.limit !== void 0)
|
|
3360
|
+
return out.slice(0, opts.limit);
|
|
3361
|
+
return out;
|
|
3362
|
+
}
|
|
3363
|
+
async function getGeminiSession(id, opts = {}) {
|
|
3364
|
+
const root = opts.root ?? DEFAULT_GEMINI_ROOT;
|
|
3365
|
+
const files = await listSessionFiles(root);
|
|
3366
|
+
let chosen;
|
|
3367
|
+
for (const file of files) {
|
|
3368
|
+
if (file.filenameId === id || id.startsWith(file.filenameId)) {
|
|
3369
|
+
chosen = file;
|
|
3370
|
+
break;
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
if (!chosen) {
|
|
3374
|
+
for (const file of files) {
|
|
3375
|
+
const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
|
|
3376
|
+
if (meta2.id === id) {
|
|
3377
|
+
chosen = file;
|
|
3378
|
+
break;
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
if (!chosen)
|
|
3383
|
+
return null;
|
|
3384
|
+
const cached = detailCache3.get(chosen.filePath);
|
|
3385
|
+
if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
|
|
3386
|
+
return cached.detail;
|
|
3387
|
+
}
|
|
3388
|
+
const { meta, events } = await parseSession(chosen);
|
|
3389
|
+
const detail = { ...meta, events };
|
|
3390
|
+
detailCache3.set(chosen.filePath, {
|
|
3391
|
+
detail,
|
|
3392
|
+
mtimeMs: chosen.mtimeMs,
|
|
3393
|
+
sizeBytes: chosen.sizeBytes
|
|
3394
|
+
});
|
|
3395
|
+
return detail;
|
|
3396
|
+
}
|
|
3397
|
+
function geminiSessionLocalDay(meta) {
|
|
3398
|
+
if (!meta.firstTimestamp)
|
|
3399
|
+
return void 0;
|
|
3400
|
+
const ms = Date.parse(meta.firstTimestamp);
|
|
3401
|
+
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
3402
|
+
}
|
|
3403
|
+
var DEFAULT_GEMINI_ROOT, GEMINI_PROJECTS_FILE, SESSION_FILE_RE, IDLE_GAP_MS2, projectsCache, metaCache3, detailCache3;
|
|
3404
|
+
var init_gemini = __esm({
|
|
3405
|
+
"../parser/dist/gemini.js"() {
|
|
3406
|
+
"use strict";
|
|
3407
|
+
init_analytics();
|
|
3408
|
+
init_user_input();
|
|
3409
|
+
DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
|
|
3410
|
+
GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
|
|
3411
|
+
SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
|
|
3412
|
+
IDLE_GAP_MS2 = 3 * 60 * 1e3;
|
|
3413
|
+
projectsCache = null;
|
|
3414
|
+
metaCache3 = /* @__PURE__ */ new Map();
|
|
3415
|
+
detailCache3 = /* @__PURE__ */ new Map();
|
|
3416
|
+
}
|
|
3417
|
+
});
|
|
3418
|
+
|
|
3419
|
+
// ../parser/dist/antigravity.js
|
|
3420
|
+
import { promises as fs4 } from "node:fs";
|
|
3421
|
+
import os4 from "node:os";
|
|
3422
|
+
import path4 from "node:path";
|
|
3423
|
+
async function safeReaddir3(p) {
|
|
3424
|
+
return fs4.readdir(p).catch(() => []);
|
|
3425
|
+
}
|
|
3426
|
+
async function loadSlugToCwd2(root) {
|
|
3427
|
+
const historyFile = path4.join(root, "history.jsonl");
|
|
3428
|
+
const stat = await fs4.stat(historyFile).catch(() => null);
|
|
3429
|
+
if (!stat)
|
|
3430
|
+
return /* @__PURE__ */ new Map();
|
|
3431
|
+
if (historyCache && historyCache.mtimeMs === stat.mtimeMs) {
|
|
3432
|
+
return historyCache.slugToCwd;
|
|
3433
|
+
}
|
|
3434
|
+
const raw = await fs4.readFile(historyFile, "utf8").catch(() => "");
|
|
3435
|
+
const slugToCwd = /* @__PURE__ */ new Map();
|
|
3436
|
+
for (const line of raw.split("\n")) {
|
|
3437
|
+
const trimmed = line.trim();
|
|
3438
|
+
if (!trimmed)
|
|
3439
|
+
continue;
|
|
3440
|
+
try {
|
|
3441
|
+
const parsed = JSON.parse(trimmed);
|
|
3442
|
+
if (parsed.conversationId && parsed.workspace) {
|
|
3443
|
+
slugToCwd.set(parsed.conversationId, parsed.workspace);
|
|
3444
|
+
}
|
|
3445
|
+
} catch {
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
historyCache = { mtimeMs: stat.mtimeMs, slugToCwd };
|
|
3449
|
+
return slugToCwd;
|
|
3450
|
+
}
|
|
3451
|
+
async function listSessionFiles2(root) {
|
|
3452
|
+
const slugToCwd = await loadSlugToCwd2(root);
|
|
3453
|
+
const out = [];
|
|
3454
|
+
const brainDir = path4.join(root, "brain");
|
|
3455
|
+
const entries = await safeReaddir3(brainDir);
|
|
3456
|
+
for (const entry of entries) {
|
|
3457
|
+
const transcriptPath = path4.join(brainDir, entry, ".system_generated", "logs", "transcript.jsonl");
|
|
3458
|
+
const stat = await fs4.stat(transcriptPath).catch(() => null);
|
|
3459
|
+
if (stat && stat.isFile()) {
|
|
3460
|
+
out.push({
|
|
3461
|
+
filePath: transcriptPath,
|
|
3462
|
+
conversationId: entry,
|
|
3463
|
+
cwd: slugToCwd.get(entry),
|
|
3464
|
+
mtimeMs: stat.mtimeMs,
|
|
3465
|
+
sizeBytes: stat.size
|
|
3466
|
+
});
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
return out;
|
|
3470
|
+
}
|
|
3471
|
+
function emptyUsage3() {
|
|
3472
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
3473
|
+
}
|
|
3474
|
+
function previewOf3(text) {
|
|
3475
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
3476
|
+
}
|
|
3477
|
+
function truncate4(s, n) {
|
|
3478
|
+
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
3479
|
+
}
|
|
3480
|
+
async function parseSession2(file) {
|
|
3481
|
+
const raw = await fs4.readFile(file.filePath, "utf8");
|
|
3482
|
+
const events = [];
|
|
3483
|
+
const totalUsage = emptyUsage3();
|
|
3484
|
+
let firstTimestamp;
|
|
3485
|
+
let lastTimestamp;
|
|
3486
|
+
let model;
|
|
3487
|
+
let toolCallCount = 0;
|
|
3488
|
+
let turnCount = 0;
|
|
3489
|
+
let firstUserPreview;
|
|
3490
|
+
let lastUserPreview;
|
|
3491
|
+
let lastAgentPreview;
|
|
3492
|
+
const tsMs = [];
|
|
3493
|
+
let idx = 0;
|
|
3494
|
+
function pushEvent(e) {
|
|
3495
|
+
events.push(e);
|
|
3496
|
+
if (e.timestamp && e.role !== "meta") {
|
|
3497
|
+
if (!firstTimestamp)
|
|
3498
|
+
firstTimestamp = e.timestamp;
|
|
3499
|
+
lastTimestamp = e.timestamp;
|
|
3500
|
+
const ms = Date.parse(e.timestamp);
|
|
3501
|
+
if (Number.isFinite(ms))
|
|
3502
|
+
tsMs.push(ms);
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
const pendingToolCalls = [];
|
|
3506
|
+
const parsedObjects = [];
|
|
3507
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
3508
|
+
for (const line of raw.split("\n")) {
|
|
3509
|
+
const trimmed = line.trim();
|
|
3510
|
+
if (!trimmed)
|
|
3511
|
+
continue;
|
|
3512
|
+
try {
|
|
3513
|
+
const obj = JSON.parse(trimmed);
|
|
3514
|
+
const stepIdx = obj.step_index;
|
|
3515
|
+
if (typeof stepIdx === "number") {
|
|
3516
|
+
if (indexMap.has(stepIdx)) {
|
|
3517
|
+
parsedObjects[indexMap.get(stepIdx)] = obj;
|
|
3518
|
+
} else {
|
|
3519
|
+
indexMap.set(stepIdx, parsedObjects.length);
|
|
3520
|
+
parsedObjects.push(obj);
|
|
3521
|
+
}
|
|
3522
|
+
} else {
|
|
3523
|
+
parsedObjects.push(obj);
|
|
3524
|
+
}
|
|
3525
|
+
} catch {
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
for (const eventObj of parsedObjects) {
|
|
3529
|
+
const ts = eventObj.created_at || eventObj.timestamp;
|
|
3530
|
+
if (eventObj.type === "USER_INPUT") {
|
|
3531
|
+
if (typeof eventObj.content === "string") {
|
|
3532
|
+
const matchNoNeed = eventObj.content.match(/Model Selection` from .*? to (.*?)\.\s*No need to/);
|
|
3533
|
+
if (matchNoNeed) {
|
|
3534
|
+
let rawModel = matchNoNeed[1].trim();
|
|
3535
|
+
rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
|
|
3536
|
+
model = rawModel;
|
|
3537
|
+
} else {
|
|
3538
|
+
const matchDot = eventObj.content.match(/Model Selection` from .*? to ([^\n]+)/);
|
|
3539
|
+
if (matchDot) {
|
|
3540
|
+
let rawModel = matchDot[1].trim();
|
|
3541
|
+
if (rawModel.endsWith(".")) {
|
|
3542
|
+
rawModel = rawModel.slice(0, -1).trim();
|
|
3543
|
+
}
|
|
3544
|
+
rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
|
|
3545
|
+
model = rawModel;
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
let text2 = eventObj.content || "";
|
|
3550
|
+
const requestMatch = text2.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
3551
|
+
if (requestMatch) {
|
|
3552
|
+
text2 = requestMatch[1].trim();
|
|
3553
|
+
}
|
|
3554
|
+
const preview = previewOf3(text2);
|
|
3555
|
+
const isHidden = isFrameworkInjectedUserInput(text2);
|
|
3556
|
+
if (text2 && !isHidden) {
|
|
3557
|
+
if (!firstUserPreview)
|
|
3558
|
+
firstUserPreview = preview;
|
|
3559
|
+
lastUserPreview = preview;
|
|
3560
|
+
turnCount += 1;
|
|
3561
|
+
}
|
|
3562
|
+
pushEvent({
|
|
3563
|
+
index: idx++,
|
|
3564
|
+
timestamp: ts,
|
|
3565
|
+
role: "user",
|
|
3566
|
+
rawType: "antigravity/user",
|
|
3567
|
+
preview,
|
|
3568
|
+
blocks: text2 ? [{ type: "text", text: text2 }] : [],
|
|
3569
|
+
messageId: eventObj.step_index?.toString(),
|
|
3570
|
+
raw: eventObj
|
|
3571
|
+
});
|
|
3572
|
+
continue;
|
|
3573
|
+
}
|
|
3574
|
+
if (eventObj.type === "PLANNER_RESPONSE") {
|
|
3575
|
+
const thinking = eventObj.thinking;
|
|
3576
|
+
const content = eventObj.content;
|
|
3577
|
+
if (thinking) {
|
|
3578
|
+
pushEvent({
|
|
3579
|
+
index: idx++,
|
|
3580
|
+
timestamp: ts,
|
|
3581
|
+
role: "agent-thinking",
|
|
3582
|
+
rawType: "antigravity/thought",
|
|
3583
|
+
preview: previewOf3(thinking),
|
|
3584
|
+
blocks: [{ type: "thinking", thinking }],
|
|
3585
|
+
model,
|
|
3586
|
+
raw: eventObj
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
if (content) {
|
|
3590
|
+
const preview = previewOf3(content);
|
|
3591
|
+
lastAgentPreview = preview;
|
|
3592
|
+
pushEvent({
|
|
3593
|
+
index: idx++,
|
|
3594
|
+
timestamp: ts,
|
|
3595
|
+
role: "agent",
|
|
3596
|
+
rawType: "antigravity/agent",
|
|
3597
|
+
preview,
|
|
3598
|
+
blocks: [{ type: "text", text: content }],
|
|
3599
|
+
messageId: eventObj.step_index?.toString(),
|
|
3600
|
+
model,
|
|
3601
|
+
raw: eventObj
|
|
3602
|
+
});
|
|
3603
|
+
}
|
|
3604
|
+
const toolCalls = eventObj.tool_calls || [];
|
|
3605
|
+
for (let cIdx = 0; cIdx < toolCalls.length; cIdx++) {
|
|
3606
|
+
const tc = toolCalls[cIdx];
|
|
3607
|
+
toolCallCount += 1;
|
|
3608
|
+
const toolUseId = `tool-${eventObj.step_index}-${cIdx}`;
|
|
3609
|
+
const argsStr = tc.args ? JSON.stringify(tc.args) : "";
|
|
3610
|
+
pendingToolCalls.push({ id: toolUseId, name: tc.name });
|
|
3611
|
+
pushEvent({
|
|
3612
|
+
index: idx++,
|
|
3613
|
+
timestamp: ts,
|
|
3614
|
+
role: "tool-call",
|
|
3615
|
+
rawType: "antigravity/tool_call",
|
|
3616
|
+
preview: `${tc.name}(${truncate4(argsStr, 80)})`,
|
|
3617
|
+
blocks: [{ type: "tool_use", id: toolUseId, name: tc.name, input: tc.args || {} }],
|
|
3618
|
+
toolName: tc.name,
|
|
3619
|
+
toolUseId,
|
|
3620
|
+
model,
|
|
3621
|
+
raw: tc
|
|
3622
|
+
});
|
|
3623
|
+
}
|
|
3624
|
+
continue;
|
|
3625
|
+
}
|
|
3626
|
+
if (eventObj.source === "MODEL" && eventObj.type !== "PLANNER_RESPONSE" && eventObj.type !== "ERROR_MESSAGE" && pendingToolCalls.length > 0) {
|
|
3627
|
+
const matchedCall = pendingToolCalls.shift();
|
|
3628
|
+
const toolUseId = matchedCall ? matchedCall.id : `tool-${eventObj.step_index}-unknown`;
|
|
3629
|
+
const contentStr = typeof eventObj.content === "string" ? eventObj.content : JSON.stringify(eventObj.content || "");
|
|
3630
|
+
const isError = eventObj.status === "ERROR" || eventObj.status === "FAILED" || eventObj.status === "CANCELED" || !!eventObj.error;
|
|
3631
|
+
pushEvent({
|
|
3632
|
+
index: idx++,
|
|
3633
|
+
timestamp: ts,
|
|
3634
|
+
role: "tool-result",
|
|
3635
|
+
rawType: "antigravity/tool_result",
|
|
3636
|
+
preview: previewOf3(contentStr),
|
|
3637
|
+
blocks: [{
|
|
3638
|
+
type: "tool_result",
|
|
3639
|
+
tool_use_id: toolUseId,
|
|
3640
|
+
content: contentStr,
|
|
3641
|
+
is_error: isError
|
|
3642
|
+
}],
|
|
3643
|
+
toolUseId,
|
|
3644
|
+
toolResult: contentStr,
|
|
3645
|
+
raw: eventObj
|
|
3646
|
+
});
|
|
3647
|
+
continue;
|
|
3648
|
+
}
|
|
3649
|
+
const text = eventObj.content || eventObj.error || "";
|
|
3650
|
+
pushEvent({
|
|
3651
|
+
index: idx++,
|
|
3652
|
+
timestamp: ts,
|
|
3653
|
+
role: "meta",
|
|
3654
|
+
rawType: `antigravity/${eventObj.type?.toLowerCase() || "unknown"}`,
|
|
3655
|
+
preview: previewOf3(text),
|
|
3656
|
+
blocks: text ? [{ type: "text", text }] : [],
|
|
3657
|
+
raw: eventObj
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
|
|
3661
|
+
if (startMs !== void 0 && Number.isFinite(startMs)) {
|
|
3662
|
+
let prevMs;
|
|
3663
|
+
for (const ev of events) {
|
|
3664
|
+
if (!ev.timestamp)
|
|
3665
|
+
continue;
|
|
3666
|
+
const ms = Date.parse(ev.timestamp);
|
|
3667
|
+
if (!Number.isFinite(ms))
|
|
3668
|
+
continue;
|
|
3669
|
+
ev.tOffsetMs = Math.max(0, ms - startMs);
|
|
3670
|
+
if (prevMs !== void 0)
|
|
3671
|
+
ev.gapMs = Math.max(0, ms - prevMs);
|
|
3672
|
+
prevMs = ms;
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
const activeSegments = computeActiveSegments4(tsMs);
|
|
3676
|
+
const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
|
|
3677
|
+
const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
|
|
3678
|
+
const sessionId = file.conversationId;
|
|
3679
|
+
const cwd = file.cwd;
|
|
3680
|
+
const projectName = cwd ? canonicalProjectName(cwd) : file.conversationId;
|
|
3681
|
+
const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.conversationId;
|
|
3682
|
+
const meta = {
|
|
3683
|
+
agent: "antigravity",
|
|
3684
|
+
id: sessionId,
|
|
3685
|
+
filePath: file.filePath,
|
|
3686
|
+
projectName,
|
|
3687
|
+
projectDir,
|
|
3688
|
+
sessionId,
|
|
3689
|
+
firstTimestamp,
|
|
3690
|
+
lastTimestamp,
|
|
3691
|
+
durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
|
|
3692
|
+
eventCount: events.length,
|
|
3693
|
+
model,
|
|
3694
|
+
cwd,
|
|
3695
|
+
totalUsage,
|
|
3696
|
+
status: "idle",
|
|
3697
|
+
firstUserPreview,
|
|
3698
|
+
lastUserPreview,
|
|
3699
|
+
lastAgentPreview,
|
|
3700
|
+
toolCallCount,
|
|
3701
|
+
turnCount,
|
|
3702
|
+
airTimeMs,
|
|
3703
|
+
activeSegments
|
|
3704
|
+
};
|
|
3705
|
+
return { meta, events };
|
|
3706
|
+
}
|
|
3707
|
+
function computeActiveSegments4(tsMs) {
|
|
3708
|
+
if (tsMs.length === 0)
|
|
3709
|
+
return [];
|
|
3710
|
+
const sorted = [...tsMs].sort((a, b) => a - b);
|
|
3711
|
+
const out = [];
|
|
3712
|
+
let segStart = sorted[0];
|
|
3713
|
+
let segEnd = sorted[0];
|
|
3714
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
3715
|
+
if (sorted[i] - segEnd > IDLE_GAP_MS3) {
|
|
3716
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3717
|
+
segStart = sorted[i];
|
|
3718
|
+
}
|
|
3719
|
+
segEnd = sorted[i];
|
|
3720
|
+
}
|
|
3721
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3722
|
+
return out;
|
|
3723
|
+
}
|
|
3724
|
+
function clearAntigravityCaches() {
|
|
3725
|
+
metaCache4.clear();
|
|
3726
|
+
detailCache4.clear();
|
|
3727
|
+
historyCache = null;
|
|
3728
|
+
}
|
|
3729
|
+
async function listAntigravitySessions(opts = {}) {
|
|
3730
|
+
const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
|
|
3731
|
+
const files = await listSessionFiles2(root);
|
|
3732
|
+
const out = [];
|
|
3733
|
+
for (const file of files) {
|
|
3734
|
+
const cached = metaCache4.get(file.filePath);
|
|
3735
|
+
if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes && cached.cwd === file.cwd) {
|
|
3736
|
+
out.push(cached.meta);
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
try {
|
|
3740
|
+
const { meta } = await parseSession2(file);
|
|
3741
|
+
metaCache4.set(file.filePath, {
|
|
3742
|
+
meta,
|
|
3743
|
+
mtimeMs: file.mtimeMs,
|
|
3744
|
+
sizeBytes: file.sizeBytes,
|
|
3745
|
+
cwd: file.cwd
|
|
3746
|
+
});
|
|
3747
|
+
out.push(meta);
|
|
3748
|
+
} catch {
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
|
|
3752
|
+
if (opts.limit !== void 0)
|
|
3753
|
+
return out.slice(0, opts.limit);
|
|
3754
|
+
return out;
|
|
3755
|
+
}
|
|
3756
|
+
async function getAntigravitySession(id, opts = {}) {
|
|
3757
|
+
const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
|
|
3758
|
+
const files = await listSessionFiles2(root);
|
|
3759
|
+
let chosen;
|
|
3760
|
+
for (const file of files) {
|
|
3761
|
+
if (file.conversationId === id) {
|
|
3762
|
+
chosen = file;
|
|
3763
|
+
break;
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
if (!chosen)
|
|
3767
|
+
return null;
|
|
3768
|
+
const cached = detailCache4.get(chosen.filePath);
|
|
3769
|
+
if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes && cached.cwd === chosen.cwd) {
|
|
3770
|
+
return cached.detail;
|
|
3771
|
+
}
|
|
3772
|
+
const { meta, events } = await parseSession2(chosen);
|
|
3773
|
+
const detail = { ...meta, events };
|
|
3774
|
+
detailCache4.set(chosen.filePath, {
|
|
3775
|
+
detail,
|
|
3776
|
+
mtimeMs: chosen.mtimeMs,
|
|
3777
|
+
sizeBytes: chosen.sizeBytes,
|
|
3778
|
+
cwd: chosen.cwd
|
|
3779
|
+
});
|
|
3780
|
+
return detail;
|
|
3781
|
+
}
|
|
3782
|
+
function antigravitySessionLocalDay(meta) {
|
|
3783
|
+
if (!meta.firstTimestamp)
|
|
3784
|
+
return void 0;
|
|
3785
|
+
const ms = Date.parse(meta.firstTimestamp);
|
|
3786
|
+
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
3787
|
+
}
|
|
3788
|
+
var DEFAULT_ANTIGRAVITY_ROOT, IDLE_GAP_MS3, historyCache, metaCache4, detailCache4;
|
|
3789
|
+
var init_antigravity = __esm({
|
|
3790
|
+
"../parser/dist/antigravity.js"() {
|
|
3791
|
+
"use strict";
|
|
3792
|
+
init_analytics();
|
|
3793
|
+
init_user_input();
|
|
3794
|
+
DEFAULT_ANTIGRAVITY_ROOT = path4.join(os4.homedir(), ".gemini", "antigravity-cli");
|
|
3795
|
+
IDLE_GAP_MS3 = 3 * 60 * 1e3;
|
|
3796
|
+
historyCache = null;
|
|
3797
|
+
metaCache4 = /* @__PURE__ */ new Map();
|
|
3798
|
+
detailCache4 = /* @__PURE__ */ new Map();
|
|
3799
|
+
}
|
|
3800
|
+
});
|
|
3801
|
+
|
|
3802
|
+
// ../parser/dist/cowork.js
|
|
3803
|
+
import { promises as fs5 } from "node:fs";
|
|
3804
|
+
import os5 from "node:os";
|
|
3805
|
+
import path5 from "node:path";
|
|
3806
|
+
function defaultCoworkRoot() {
|
|
3807
|
+
const home = os5.homedir();
|
|
3808
|
+
if (process.platform === "darwin") {
|
|
3809
|
+
return path5.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions");
|
|
3810
|
+
}
|
|
3811
|
+
if (process.platform === "win32") {
|
|
3812
|
+
const appData = process.env.APPDATA ?? path5.join(home, "AppData", "Roaming");
|
|
3813
|
+
return path5.join(appData, "Claude", "local-agent-mode-sessions");
|
|
3814
|
+
}
|
|
3815
|
+
return path5.join(home, ".config", "Claude", "local-agent-mode-sessions");
|
|
3816
|
+
}
|
|
3817
|
+
async function safeReaddir4(p) {
|
|
3818
|
+
return fs5.readdir(p).catch(() => []);
|
|
3819
|
+
}
|
|
3820
|
+
async function statMs(p) {
|
|
3821
|
+
const s = await fs5.stat(p).catch(() => null);
|
|
3822
|
+
return s ? s.mtimeMs : 0;
|
|
3823
|
+
}
|
|
3824
|
+
async function listSessionFiles3(root) {
|
|
3825
|
+
const out = [];
|
|
3826
|
+
const accounts = await safeReaddir4(root);
|
|
3827
|
+
for (const accountId of accounts) {
|
|
3828
|
+
const accountDir = path5.join(root, accountId);
|
|
3829
|
+
const workspaces = await safeReaddir4(accountDir);
|
|
3830
|
+
for (const workspaceId of workspaces) {
|
|
3831
|
+
const workspaceDir = path5.join(accountDir, workspaceId);
|
|
3832
|
+
const spacesMtimeMs = await statMs(path5.join(workspaceDir, "spaces.json"));
|
|
3833
|
+
const entries = await safeReaddir4(workspaceDir);
|
|
3834
|
+
for (const entry of entries) {
|
|
3835
|
+
if (!SESSION_ID_RE.test(entry))
|
|
3836
|
+
continue;
|
|
3837
|
+
const auditPath = path5.join(workspaceDir, entry, "audit.jsonl");
|
|
3838
|
+
const auditStat = await fs5.stat(auditPath).catch(() => null);
|
|
3839
|
+
if (!auditStat || !auditStat.isFile() || auditStat.size === 0)
|
|
3840
|
+
continue;
|
|
3841
|
+
const metaPath = path5.join(workspaceDir, `${entry}.json`);
|
|
3842
|
+
const metaMtimeMs = await statMs(metaPath);
|
|
3843
|
+
out.push({
|
|
3844
|
+
sessionId: entry,
|
|
3845
|
+
auditPath,
|
|
3846
|
+
metaPath,
|
|
3847
|
+
workspaceDir,
|
|
3848
|
+
auditMtimeMs: auditStat.mtimeMs,
|
|
3849
|
+
auditSize: auditStat.size,
|
|
3850
|
+
metaMtimeMs,
|
|
3851
|
+
spacesMtimeMs
|
|
3852
|
+
});
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
return out;
|
|
3857
|
+
}
|
|
3858
|
+
async function loadSpacesForWorkspace(workspaceDir) {
|
|
3859
|
+
const spacesPath = path5.join(workspaceDir, "spaces.json");
|
|
3860
|
+
const stat = await fs5.stat(spacesPath).catch(() => null);
|
|
3861
|
+
if (!stat)
|
|
3862
|
+
return /* @__PURE__ */ new Map();
|
|
3863
|
+
const cached = spacesCache.get(workspaceDir);
|
|
3864
|
+
if (cached && cached.mtimeMs === stat.mtimeMs)
|
|
3865
|
+
return cached.spaceIdToPath;
|
|
3866
|
+
const raw = await fs5.readFile(spacesPath, "utf8").catch(() => "");
|
|
3867
|
+
const out = /* @__PURE__ */ new Map();
|
|
3868
|
+
try {
|
|
3869
|
+
const parsed = JSON.parse(raw);
|
|
3870
|
+
for (const space of parsed.spaces ?? []) {
|
|
3871
|
+
const id = typeof space.id === "string" ? space.id : void 0;
|
|
3872
|
+
const folders = Array.isArray(space.folders) ? space.folders : [];
|
|
3873
|
+
const first = folders[0];
|
|
3874
|
+
const folderPath = typeof first?.path === "string" ? first.path : void 0;
|
|
3875
|
+
if (id && folderPath)
|
|
3876
|
+
out.set(id, folderPath);
|
|
3877
|
+
}
|
|
3878
|
+
} catch {
|
|
3879
|
+
}
|
|
3880
|
+
spacesCache.set(workspaceDir, { mtimeMs: stat.mtimeMs, spaceIdToPath: out });
|
|
3881
|
+
return out;
|
|
3882
|
+
}
|
|
3883
|
+
async function readCoworkMeta(metaPath) {
|
|
3884
|
+
const raw = await fs5.readFile(metaPath, "utf8").catch(() => "");
|
|
3885
|
+
if (!raw)
|
|
3886
|
+
return {};
|
|
3887
|
+
try {
|
|
3888
|
+
const j = JSON.parse(raw);
|
|
3889
|
+
return {
|
|
3890
|
+
spaceId: typeof j.spaceId === "string" ? j.spaceId : void 0,
|
|
3891
|
+
userSelectedFolders: Array.isArray(j.userSelectedFolders) ? j.userSelectedFolders.filter((s) => typeof s === "string") : void 0,
|
|
3892
|
+
cwd: typeof j.cwd === "string" ? j.cwd : void 0,
|
|
3893
|
+
model: typeof j.model === "string" ? j.model : void 0,
|
|
3894
|
+
title: typeof j.title === "string" ? j.title : void 0,
|
|
3895
|
+
createdAt: typeof j.createdAt === "number" ? j.createdAt : void 0,
|
|
3896
|
+
lastActivityAt: typeof j.lastActivityAt === "number" ? j.lastActivityAt : void 0
|
|
3897
|
+
};
|
|
3898
|
+
} catch {
|
|
3899
|
+
return {};
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
function resolveProject(meta, spaceIdToPath) {
|
|
3903
|
+
let projectPath;
|
|
3904
|
+
if (meta.spaceId)
|
|
3905
|
+
projectPath = spaceIdToPath.get(meta.spaceId);
|
|
3906
|
+
if (!projectPath && meta.userSelectedFolders && meta.userSelectedFolders.length > 0) {
|
|
3907
|
+
projectPath = meta.userSelectedFolders[0];
|
|
3908
|
+
}
|
|
3909
|
+
if (!projectPath) {
|
|
3910
|
+
return { projectName: "cowork:unspaced", projectDir: "cowork-unspaced" };
|
|
3911
|
+
}
|
|
3912
|
+
return {
|
|
3913
|
+
projectName: canonicalProjectName(projectPath),
|
|
3914
|
+
projectDir: projectPath.replace(/^\//, "-").replace(/\//g, "-"),
|
|
3915
|
+
cwd: projectPath
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
async function readJsonl2(filePath) {
|
|
3919
|
+
const raw = await fs5.readFile(filePath, "utf8");
|
|
3920
|
+
const out = [];
|
|
3921
|
+
for (const line of raw.split("\n")) {
|
|
3922
|
+
const trimmed = line.trim();
|
|
3923
|
+
if (!trimmed)
|
|
3924
|
+
continue;
|
|
3925
|
+
try {
|
|
3926
|
+
out.push(JSON.parse(trimmed));
|
|
3927
|
+
} catch {
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
return out;
|
|
3931
|
+
}
|
|
3932
|
+
async function parseCoworkSession(file) {
|
|
3933
|
+
const [lines, coworkMeta, spaceIdToPath] = await Promise.all([
|
|
3934
|
+
readJsonl2(file.auditPath),
|
|
3935
|
+
readCoworkMeta(file.metaPath),
|
|
3936
|
+
loadSpacesForWorkspace(file.workspaceDir)
|
|
3937
|
+
]);
|
|
3938
|
+
const { meta: baseMeta, events } = parseTranscript(lines);
|
|
3939
|
+
const { projectName, projectDir, cwd } = resolveProject(coworkMeta, spaceIdToPath);
|
|
2847
3940
|
const meta = {
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
3941
|
+
...baseMeta,
|
|
3942
|
+
agent: "cowork",
|
|
3943
|
+
id: file.sessionId,
|
|
3944
|
+
sessionId: file.sessionId,
|
|
3945
|
+
filePath: file.auditPath,
|
|
2851
3946
|
projectName,
|
|
2852
3947
|
projectDir,
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
lastTimestamp,
|
|
2856
|
-
durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
|
|
2857
|
-
eventCount: events.length,
|
|
2858
|
-
model,
|
|
2859
|
-
cwd,
|
|
2860
|
-
totalUsage,
|
|
2861
|
-
status: "idle",
|
|
2862
|
-
firstUserPreview,
|
|
2863
|
-
lastUserPreview,
|
|
2864
|
-
lastAgentPreview,
|
|
2865
|
-
toolCallCount,
|
|
2866
|
-
turnCount,
|
|
2867
|
-
airTimeMs,
|
|
2868
|
-
activeSegments
|
|
3948
|
+
cwd: cwd ?? baseMeta.cwd,
|
|
3949
|
+
model: baseMeta.model ?? coworkMeta.model
|
|
2869
3950
|
};
|
|
2870
3951
|
return { meta, events };
|
|
2871
3952
|
}
|
|
2872
|
-
function
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
2880
|
-
if (sorted[i] - segEnd > IDLE_GAP_MS2) {
|
|
2881
|
-
out.push({ startMs: segStart, endMs: segEnd });
|
|
2882
|
-
segStart = sorted[i];
|
|
2883
|
-
}
|
|
2884
|
-
segEnd = sorted[i];
|
|
2885
|
-
}
|
|
2886
|
-
out.push({ startMs: segStart, endMs: segEnd });
|
|
2887
|
-
return out;
|
|
3953
|
+
function cacheKeyFor(file) {
|
|
3954
|
+
return {
|
|
3955
|
+
auditMtimeMs: file.auditMtimeMs,
|
|
3956
|
+
auditSize: file.auditSize,
|
|
3957
|
+
metaMtimeMs: file.metaMtimeMs,
|
|
3958
|
+
spacesMtimeMs: file.spacesMtimeMs
|
|
3959
|
+
};
|
|
2888
3960
|
}
|
|
2889
|
-
function
|
|
2890
|
-
|
|
2891
|
-
detailCache3.clear();
|
|
2892
|
-
projectsCache = null;
|
|
3961
|
+
function cacheKeyMatches(a, b) {
|
|
3962
|
+
return a.auditMtimeMs === b.auditMtimeMs && a.auditSize === b.auditSize && a.metaMtimeMs === b.metaMtimeMs && a.spacesMtimeMs === b.spacesMtimeMs;
|
|
2893
3963
|
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3964
|
+
function clearCoworkCaches() {
|
|
3965
|
+
metaCache5.clear();
|
|
3966
|
+
detailCache5.clear();
|
|
3967
|
+
spacesCache.clear();
|
|
3968
|
+
}
|
|
3969
|
+
async function listCoworkSessions(opts = {}) {
|
|
3970
|
+
const root = opts.root ?? DEFAULT_COWORK_ROOT;
|
|
3971
|
+
const files = await listSessionFiles3(root);
|
|
2897
3972
|
const out = [];
|
|
2898
3973
|
for (const file of files) {
|
|
2899
|
-
const
|
|
2900
|
-
|
|
3974
|
+
const key = cacheKeyFor(file);
|
|
3975
|
+
const cached = metaCache5.get(file.auditPath);
|
|
3976
|
+
if (cached && cacheKeyMatches(cached.key, key)) {
|
|
2901
3977
|
out.push(cached.meta);
|
|
2902
3978
|
continue;
|
|
2903
3979
|
}
|
|
2904
3980
|
try {
|
|
2905
|
-
const { meta } = await
|
|
2906
|
-
|
|
2907
|
-
meta,
|
|
2908
|
-
mtimeMs: file.mtimeMs,
|
|
2909
|
-
sizeBytes: file.sizeBytes
|
|
2910
|
-
});
|
|
3981
|
+
const { meta } = await parseCoworkSession(file);
|
|
3982
|
+
metaCache5.set(file.auditPath, { meta, key });
|
|
2911
3983
|
out.push(meta);
|
|
2912
3984
|
} catch {
|
|
2913
3985
|
}
|
|
@@ -2917,59 +3989,38 @@ async function listGeminiSessions(opts = {}) {
|
|
|
2917
3989
|
return out.slice(0, opts.limit);
|
|
2918
3990
|
return out;
|
|
2919
3991
|
}
|
|
2920
|
-
async function
|
|
2921
|
-
const root = opts.root ??
|
|
2922
|
-
const files = await
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
if (file.filenameId === id || id.startsWith(file.filenameId)) {
|
|
2926
|
-
chosen = file;
|
|
2927
|
-
break;
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
if (!chosen) {
|
|
2931
|
-
for (const file of files) {
|
|
2932
|
-
const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
|
|
2933
|
-
if (meta2.id === id) {
|
|
2934
|
-
chosen = file;
|
|
2935
|
-
break;
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
if (!chosen)
|
|
3992
|
+
async function getCoworkSession(id, opts = {}) {
|
|
3993
|
+
const root = opts.root ?? DEFAULT_COWORK_ROOT;
|
|
3994
|
+
const files = await listSessionFiles3(root);
|
|
3995
|
+
const file = files.find((f) => f.sessionId === id);
|
|
3996
|
+
if (!file)
|
|
2940
3997
|
return null;
|
|
2941
|
-
const
|
|
2942
|
-
|
|
3998
|
+
const key = cacheKeyFor(file);
|
|
3999
|
+
const cached = detailCache5.get(file.auditPath);
|
|
4000
|
+
if (cached && cacheKeyMatches(cached.key, key))
|
|
2943
4001
|
return cached.detail;
|
|
2944
|
-
}
|
|
2945
|
-
const { meta, events } = await parseSession(chosen);
|
|
4002
|
+
const { meta, events } = await parseCoworkSession(file);
|
|
2946
4003
|
const detail = { ...meta, events };
|
|
2947
|
-
|
|
2948
|
-
detail,
|
|
2949
|
-
mtimeMs: chosen.mtimeMs,
|
|
2950
|
-
sizeBytes: chosen.sizeBytes
|
|
2951
|
-
});
|
|
4004
|
+
detailCache5.set(file.auditPath, { detail, key });
|
|
2952
4005
|
return detail;
|
|
2953
4006
|
}
|
|
2954
|
-
function
|
|
4007
|
+
function coworkSessionLocalDay(meta) {
|
|
2955
4008
|
if (!meta.firstTimestamp)
|
|
2956
4009
|
return void 0;
|
|
2957
4010
|
const ms = Date.parse(meta.firstTimestamp);
|
|
2958
4011
|
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
2959
4012
|
}
|
|
2960
|
-
var
|
|
2961
|
-
var
|
|
2962
|
-
"../parser/dist/
|
|
4013
|
+
var DEFAULT_COWORK_ROOT, SESSION_ID_RE, spacesCache, metaCache5, detailCache5;
|
|
4014
|
+
var init_cowork = __esm({
|
|
4015
|
+
"../parser/dist/cowork.js"() {
|
|
2963
4016
|
"use strict";
|
|
2964
4017
|
init_analytics();
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
metaCache3 = /* @__PURE__ */ new Map();
|
|
2972
|
-
detailCache3 = /* @__PURE__ */ new Map();
|
|
4018
|
+
init_parser();
|
|
4019
|
+
DEFAULT_COWORK_ROOT = defaultCoworkRoot();
|
|
4020
|
+
SESSION_ID_RE = /^local_[0-9a-f-]+$/;
|
|
4021
|
+
spacesCache = /* @__PURE__ */ new Map();
|
|
4022
|
+
metaCache5 = /* @__PURE__ */ new Map();
|
|
4023
|
+
detailCache5 = /* @__PURE__ */ new Map();
|
|
2973
4024
|
}
|
|
2974
4025
|
});
|
|
2975
4026
|
|
|
@@ -3017,11 +4068,14 @@ var init_team_wire = __esm({
|
|
|
3017
4068
|
// ../parser/dist/fs.js
|
|
3018
4069
|
var fs_exports = {};
|
|
3019
4070
|
__export(fs_exports, {
|
|
4071
|
+
DEFAULT_ANTIGRAVITY_ROOT: () => DEFAULT_ANTIGRAVITY_ROOT,
|
|
3020
4072
|
DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
|
|
4073
|
+
DEFAULT_COWORK_ROOT: () => DEFAULT_COWORK_ROOT,
|
|
3021
4074
|
DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
|
|
3022
4075
|
DEFAULT_ROOT: () => DEFAULT_ROOT,
|
|
3023
4076
|
RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
|
|
3024
4077
|
agentSources: () => agentSources,
|
|
4078
|
+
antigravitySessionLocalDay: () => antigravitySessionLocalDay,
|
|
3025
4079
|
buildCalibrationCurve: () => buildCalibrationCurve,
|
|
3026
4080
|
cacheStats: () => cacheStats,
|
|
3027
4081
|
cclensHome: () => cclensHome,
|
|
@@ -3029,19 +4083,24 @@ __export(fs_exports, {
|
|
|
3029
4083
|
clearCaches: () => clearCaches,
|
|
3030
4084
|
clearTeamConfig: () => clearTeamConfig,
|
|
3031
4085
|
codexSessionLocalDay: () => codexSessionLocalDay,
|
|
4086
|
+
coworkSessionLocalDay: () => coworkSessionLocalDay,
|
|
3032
4087
|
decodeProjectName: () => decodeProjectName,
|
|
3033
4088
|
findTeamLead: () => findTeamLead,
|
|
3034
4089
|
geminiSessionLocalDay: () => geminiSessionLocalDay,
|
|
3035
4090
|
getAgentSource: () => getAgentSource,
|
|
4091
|
+
getAntigravitySession: () => getAntigravitySession,
|
|
3036
4092
|
getAnySession: () => getAnySession,
|
|
3037
4093
|
getCodexSession: () => getCodexSession,
|
|
4094
|
+
getCoworkSession: () => getCoworkSession,
|
|
3038
4095
|
getGeminiSession: () => getGeminiSession,
|
|
3039
4096
|
getLatestCodexUsage: () => getLatestCodexUsage,
|
|
3040
4097
|
getSession: () => getSession,
|
|
3041
4098
|
invalidateFile: () => invalidateFile,
|
|
3042
4099
|
isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
|
|
3043
4100
|
listAllSessions: () => listAllSessions,
|
|
4101
|
+
listAntigravitySessions: () => listAntigravitySessions,
|
|
3044
4102
|
listCodexSessions: () => listCodexSessions,
|
|
4103
|
+
listCoworkSessions: () => listCoworkSessions,
|
|
3045
4104
|
listGeminiSessions: () => listGeminiSessions,
|
|
3046
4105
|
listProjects: () => listProjects,
|
|
3047
4106
|
listSessions: () => listSessions,
|
|
@@ -3050,20 +4109,21 @@ __export(fs_exports, {
|
|
|
3050
4109
|
loadCalibrationSnapshots: () => loadCalibrationSnapshots,
|
|
3051
4110
|
loadTeamForSession: () => loadTeamForSession,
|
|
3052
4111
|
loadUsageByDay: () => loadUsageByDay,
|
|
4112
|
+
loadWorkflowAgentDetail: () => loadWorkflowAgentDetail,
|
|
3053
4113
|
readJsonlFile: () => readJsonlFile,
|
|
3054
4114
|
readTeamConfig: () => readTeamConfig,
|
|
3055
4115
|
sessionIdFromFileName: () => sessionIdFromFileName,
|
|
3056
4116
|
walkJsonlFiles: () => walkJsonlFiles,
|
|
3057
4117
|
writeTeamConfig: () => writeTeamConfig
|
|
3058
4118
|
});
|
|
3059
|
-
import { promises as
|
|
3060
|
-
import
|
|
3061
|
-
import
|
|
4119
|
+
import { promises as fs6 } from "node:fs";
|
|
4120
|
+
import os6 from "node:os";
|
|
4121
|
+
import path6 from "node:path";
|
|
3062
4122
|
function cclensHome() {
|
|
3063
|
-
return process.env.CCLENS_HOME ||
|
|
4123
|
+
return process.env.CCLENS_HOME || path6.join(os6.homedir(), ".cclens");
|
|
3064
4124
|
}
|
|
3065
4125
|
function cclensPath(...parts) {
|
|
3066
|
-
return
|
|
4126
|
+
return path6.join(cclensHome(), ...parts);
|
|
3067
4127
|
}
|
|
3068
4128
|
function cacheStats() {
|
|
3069
4129
|
return claudeCodeCacheStats();
|
|
@@ -3072,6 +4132,8 @@ function clearCaches() {
|
|
|
3072
4132
|
clearClaudeCodeCaches();
|
|
3073
4133
|
clearCodexCaches();
|
|
3074
4134
|
clearGeminiCaches();
|
|
4135
|
+
clearAntigravityCaches();
|
|
4136
|
+
clearCoworkCaches();
|
|
3075
4137
|
}
|
|
3076
4138
|
function invalidateFile(fullPath) {
|
|
3077
4139
|
invalidateClaudeCodeFile(fullPath);
|
|
@@ -3103,7 +4165,7 @@ function usageLogPath() {
|
|
|
3103
4165
|
async function loadUsageByDay(start, end) {
|
|
3104
4166
|
let raw;
|
|
3105
4167
|
try {
|
|
3106
|
-
raw = await
|
|
4168
|
+
raw = await fs6.readFile(usageLogPath(), "utf8");
|
|
3107
4169
|
} catch {
|
|
3108
4170
|
return { by_day: [] };
|
|
3109
4171
|
}
|
|
@@ -3148,7 +4210,7 @@ async function loadUsageByDay(start, end) {
|
|
|
3148
4210
|
async function loadCalibrationSnapshots() {
|
|
3149
4211
|
let raw;
|
|
3150
4212
|
try {
|
|
3151
|
-
raw = await
|
|
4213
|
+
raw = await fs6.readFile(usageLogPath(), "utf8");
|
|
3152
4214
|
} catch {
|
|
3153
4215
|
return [];
|
|
3154
4216
|
}
|
|
@@ -3306,7 +4368,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
|
|
|
3306
4368
|
]);
|
|
3307
4369
|
return buildCalibrationCurve(events, snapshots, tier, granularityMin);
|
|
3308
4370
|
}
|
|
3309
|
-
var codexSource, geminiSource, agentSources;
|
|
4371
|
+
var codexSource, geminiSource, antigravitySource, coworkSource, agentSources;
|
|
3310
4372
|
var init_fs = __esm({
|
|
3311
4373
|
"../parser/dist/fs.js"() {
|
|
3312
4374
|
"use strict";
|
|
@@ -3316,9 +4378,13 @@ var init_fs = __esm({
|
|
|
3316
4378
|
init_claude_code();
|
|
3317
4379
|
init_codex();
|
|
3318
4380
|
init_gemini();
|
|
4381
|
+
init_antigravity();
|
|
4382
|
+
init_cowork();
|
|
3319
4383
|
init_claude_code();
|
|
3320
4384
|
init_codex();
|
|
3321
4385
|
init_gemini();
|
|
4386
|
+
init_antigravity();
|
|
4387
|
+
init_cowork();
|
|
3322
4388
|
init_team_config();
|
|
3323
4389
|
init_team_wire();
|
|
3324
4390
|
codexSource = {
|
|
@@ -3352,7 +4418,33 @@ var init_fs = __esm({
|
|
|
3352
4418
|
return getGeminiSession(id);
|
|
3353
4419
|
}
|
|
3354
4420
|
};
|
|
3355
|
-
|
|
4421
|
+
antigravitySource = {
|
|
4422
|
+
...ANTIGRAVITY_METADATA,
|
|
4423
|
+
defaultRoot: DEFAULT_ANTIGRAVITY_ROOT,
|
|
4424
|
+
async listSessions(opts) {
|
|
4425
|
+
return listAntigravitySessions(opts);
|
|
4426
|
+
},
|
|
4427
|
+
async getSession(id) {
|
|
4428
|
+
return getAntigravitySession(id);
|
|
4429
|
+
}
|
|
4430
|
+
};
|
|
4431
|
+
coworkSource = {
|
|
4432
|
+
...COWORK_METADATA,
|
|
4433
|
+
defaultRoot: DEFAULT_COWORK_ROOT,
|
|
4434
|
+
async listSessions(opts) {
|
|
4435
|
+
return listCoworkSessions(opts);
|
|
4436
|
+
},
|
|
4437
|
+
async getSession(id) {
|
|
4438
|
+
return getCoworkSession(id);
|
|
4439
|
+
}
|
|
4440
|
+
};
|
|
4441
|
+
agentSources = [
|
|
4442
|
+
claudeCodeSource,
|
|
4443
|
+
codexSource,
|
|
4444
|
+
geminiSource,
|
|
4445
|
+
antigravitySource,
|
|
4446
|
+
coworkSource
|
|
4447
|
+
];
|
|
3356
4448
|
}
|
|
3357
4449
|
});
|
|
3358
4450
|
|
|
@@ -3764,8 +4856,10 @@ var init_aggregate = __esm({
|
|
|
3764
4856
|
// ../parser/dist/index.js
|
|
3765
4857
|
var dist_exports = {};
|
|
3766
4858
|
__export(dist_exports, {
|
|
4859
|
+
ANTIGRAVITY_METADATA: () => ANTIGRAVITY_METADATA,
|
|
3767
4860
|
CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
|
|
3768
4861
|
CODEX_METADATA: () => CODEX_METADATA,
|
|
4862
|
+
COWORK_METADATA: () => COWORK_METADATA,
|
|
3769
4863
|
GEMINI_METADATA: () => GEMINI_METADATA,
|
|
3770
4864
|
PRICES: () => PRICES,
|
|
3771
4865
|
RATE_PER_PCT: () => RATE_PER_PCT,
|
|
@@ -3806,6 +4900,7 @@ __export(dist_exports, {
|
|
|
3806
4900
|
predictUtilization: () => predictUtilization,
|
|
3807
4901
|
priorCalendarMonth: () => priorCalendarMonth,
|
|
3808
4902
|
priorCalendarWeek: () => priorCalendarWeek,
|
|
4903
|
+
projectRepoName: () => projectRepoName,
|
|
3809
4904
|
rowPrimaryIndex: () => rowPrimaryIndex,
|
|
3810
4905
|
sessionAirTimeMs: () => sessionAirTimeMs,
|
|
3811
4906
|
sessionDay: () => sessionDay,
|
|
@@ -3830,10 +4925,198 @@ var init_dist = __esm({
|
|
|
3830
4925
|
}
|
|
3831
4926
|
});
|
|
3832
4927
|
|
|
4928
|
+
// src/perception/file-probe.ts
|
|
4929
|
+
var file_probe_exports = {};
|
|
4930
|
+
__export(file_probe_exports, {
|
|
4931
|
+
pathHash: () => pathHash,
|
|
4932
|
+
probeArtifactSignals: () => probeArtifactSignals
|
|
4933
|
+
});
|
|
4934
|
+
import { createHash } from "node:crypto";
|
|
4935
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
|
|
4936
|
+
import { homedir as homedir2 } from "node:os";
|
|
4937
|
+
import { join as join7, relative, resolve as resolve2, sep } from "node:path";
|
|
4938
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
4939
|
+
function pathHash(relPath) {
|
|
4940
|
+
return createHash("sha256").update(relPath.split(sep).join("/")).digest("hex").slice(0, 32);
|
|
4941
|
+
}
|
|
4942
|
+
function defaultScanRoots(extraRoots = []) {
|
|
4943
|
+
const roots = [];
|
|
4944
|
+
const home = join7(homedir2(), ".claude");
|
|
4945
|
+
if (existsSync6(home)) roots.push({ root: home, label: "user" });
|
|
4946
|
+
for (const e of extraRoots) {
|
|
4947
|
+
const r = resolve2(e, ".claude");
|
|
4948
|
+
if (existsSync6(r) && r !== home) roots.push({ root: r, label: "project" });
|
|
4949
|
+
}
|
|
4950
|
+
return roots;
|
|
4951
|
+
}
|
|
4952
|
+
function listMarkdownFiles(dir) {
|
|
4953
|
+
if (!existsSync6(dir)) return [];
|
|
4954
|
+
const out = [];
|
|
4955
|
+
let entries;
|
|
4956
|
+
try {
|
|
4957
|
+
entries = readdirSync3(dir);
|
|
4958
|
+
} catch {
|
|
4959
|
+
return [];
|
|
4960
|
+
}
|
|
4961
|
+
for (const name of entries) {
|
|
4962
|
+
if (name.startsWith(".")) continue;
|
|
4963
|
+
const full = join7(dir, name);
|
|
4964
|
+
let stat;
|
|
4965
|
+
try {
|
|
4966
|
+
stat = statSync3(full);
|
|
4967
|
+
} catch {
|
|
4968
|
+
continue;
|
|
4969
|
+
}
|
|
4970
|
+
if (stat.isDirectory()) {
|
|
4971
|
+
out.push(...listMarkdownFiles(full));
|
|
4972
|
+
} else if (stat.isFile() && name.endsWith(".md")) {
|
|
4973
|
+
out.push(full);
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
return out;
|
|
4977
|
+
}
|
|
4978
|
+
function firstSeenDateOf(file) {
|
|
4979
|
+
try {
|
|
4980
|
+
const out = execFileSync2(
|
|
4981
|
+
"git",
|
|
4982
|
+
["log", "--diff-filter=A", "--follow", "--format=%cs", "--", file],
|
|
4983
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname6(file) }
|
|
4984
|
+
).trim().split("\n").filter(Boolean);
|
|
4985
|
+
if (out.length > 0) return out[out.length - 1];
|
|
4986
|
+
} catch {
|
|
4987
|
+
}
|
|
4988
|
+
try {
|
|
4989
|
+
const s = statSync3(file);
|
|
4990
|
+
return new Date((s.birthtime || s.mtime).getTime()).toISOString().slice(0, 10);
|
|
4991
|
+
} catch {
|
|
4992
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4995
|
+
function dirname6(p) {
|
|
4996
|
+
const i = p.lastIndexOf(sep);
|
|
4997
|
+
return i < 0 ? "." : p.slice(0, i);
|
|
4998
|
+
}
|
|
4999
|
+
function detectGitEmail(cwd) {
|
|
5000
|
+
try {
|
|
5001
|
+
return execFileSync2("git", ["config", "user.email"], {
|
|
5002
|
+
encoding: "utf8",
|
|
5003
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
5004
|
+
cwd
|
|
5005
|
+
}).trim() || null;
|
|
5006
|
+
} catch {
|
|
5007
|
+
return null;
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
function todayLocal() {
|
|
5011
|
+
const d = /* @__PURE__ */ new Date();
|
|
5012
|
+
const y = d.getFullYear();
|
|
5013
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
5014
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
5015
|
+
return `${y}-${m}-${day}`;
|
|
5016
|
+
}
|
|
5017
|
+
function scanAuthored(roots, subdir, day) {
|
|
5018
|
+
const out = [];
|
|
5019
|
+
for (const r of roots) {
|
|
5020
|
+
const dir = join7(r.root, subdir);
|
|
5021
|
+
if (!existsSync6(dir)) continue;
|
|
5022
|
+
for (const f of listMarkdownFiles(dir)) {
|
|
5023
|
+
const firstSeen = firstSeenDateOf(f);
|
|
5024
|
+
if (firstSeen !== day) continue;
|
|
5025
|
+
const rel = relative(dir, f);
|
|
5026
|
+
out.push({ pathHash: pathHash(`${r.label}:${subdir}:${rel}`), firstSeenDate: firstSeen });
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
5029
|
+
return out;
|
|
5030
|
+
}
|
|
5031
|
+
function scanEdited(roots, day) {
|
|
5032
|
+
const out = [];
|
|
5033
|
+
for (const r of roots) {
|
|
5034
|
+
const dir = join7(r.root, "skills");
|
|
5035
|
+
if (!existsSync6(dir)) continue;
|
|
5036
|
+
for (const f of listMarkdownFiles(dir)) {
|
|
5037
|
+
const firstSeen = firstSeenDateOf(f);
|
|
5038
|
+
if (firstSeen === day) continue;
|
|
5039
|
+
let stat;
|
|
5040
|
+
try {
|
|
5041
|
+
stat = statSync3(f);
|
|
5042
|
+
} catch {
|
|
5043
|
+
continue;
|
|
5044
|
+
}
|
|
5045
|
+
const mtimeDay = new Date(stat.mtime.getTime()).toISOString().slice(0, 10);
|
|
5046
|
+
if (mtimeDay !== day) continue;
|
|
5047
|
+
const rel = relative(dir, f);
|
|
5048
|
+
out.push({ pathHash: pathHash(`${r.label}:skills:${rel}`), lineDelta: 0 });
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
return out;
|
|
5052
|
+
}
|
|
5053
|
+
function claudemdLineDelta(extraRoots, authorEmail, day) {
|
|
5054
|
+
let delta = 0;
|
|
5055
|
+
const candidates = [];
|
|
5056
|
+
for (const e of extraRoots) {
|
|
5057
|
+
const f = resolve2(e, "CLAUDE.md");
|
|
5058
|
+
if (existsSync6(f)) candidates.push(f);
|
|
5059
|
+
}
|
|
5060
|
+
const homeClaudeMd = join7(homedir2(), "CLAUDE.md");
|
|
5061
|
+
if (existsSync6(homeClaudeMd)) candidates.push(homeClaudeMd);
|
|
5062
|
+
for (const file of candidates) {
|
|
5063
|
+
try {
|
|
5064
|
+
const out = execFileSync2(
|
|
5065
|
+
"git",
|
|
5066
|
+
["log", "--numstat", "--format=COMMIT %cs %ae", "--", file],
|
|
5067
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname6(file) }
|
|
5068
|
+
);
|
|
5069
|
+
let currentDate = "";
|
|
5070
|
+
let currentEmail = "";
|
|
5071
|
+
for (const line of out.split("\n")) {
|
|
5072
|
+
if (line.startsWith("COMMIT ")) {
|
|
5073
|
+
const parts = line.slice("COMMIT ".length).trim().split(/\s+/);
|
|
5074
|
+
currentDate = parts[0] ?? "";
|
|
5075
|
+
currentEmail = parts.slice(1).join(" ");
|
|
5076
|
+
} else if (currentDate === day && line.trim().length > 0) {
|
|
5077
|
+
if (authorEmail && currentEmail !== authorEmail) continue;
|
|
5078
|
+
const parts = line.split(/\s+/);
|
|
5079
|
+
const added = Number(parts[0]);
|
|
5080
|
+
const removed = Number(parts[1]);
|
|
5081
|
+
if (Number.isFinite(added) && Number.isFinite(removed)) {
|
|
5082
|
+
delta += added - removed;
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
} catch {
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
return delta;
|
|
5090
|
+
}
|
|
5091
|
+
function probeArtifactSignals(opts = {}) {
|
|
5092
|
+
const day = opts.day ?? todayLocal();
|
|
5093
|
+
const roots = defaultScanRoots(opts.extraRoots);
|
|
5094
|
+
const skillsAuthored = scanAuthored(roots, "skills", day);
|
|
5095
|
+
const subagentsAuthored = scanAuthored(roots, "agents", day);
|
|
5096
|
+
const slashCommandsAuthored = scanAuthored(roots, "commands", day);
|
|
5097
|
+
const skillsEdited = scanEdited(roots, day);
|
|
5098
|
+
const authorEmail = opts.authorEmail ?? detectGitEmail(opts.extraRoots?.[0] ?? process.cwd()) ?? void 0;
|
|
5099
|
+
const claudemd = claudemdLineDelta(opts.extraRoots ?? [], authorEmail, day);
|
|
5100
|
+
const empty = skillsAuthored.length === 0 && subagentsAuthored.length === 0 && slashCommandsAuthored.length === 0 && skillsEdited.length === 0 && claudemd === 0;
|
|
5101
|
+
if (empty) return null;
|
|
5102
|
+
return {
|
|
5103
|
+
skillsAuthored,
|
|
5104
|
+
skillsEdited,
|
|
5105
|
+
subagentsAuthored,
|
|
5106
|
+
slashCommandsAuthored,
|
|
5107
|
+
claudemdLineDelta: claudemd
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
5110
|
+
var init_file_probe = __esm({
|
|
5111
|
+
"src/perception/file-probe.ts"() {
|
|
5112
|
+
"use strict";
|
|
5113
|
+
}
|
|
5114
|
+
});
|
|
5115
|
+
|
|
3833
5116
|
// src/daemon-worker.ts
|
|
3834
5117
|
import { spawn as spawn2 } from "node:child_process";
|
|
3835
|
-
import { appendFileSync as appendFileSync5, closeSync, existsSync as
|
|
3836
|
-
import { dirname as
|
|
5118
|
+
import { appendFileSync as appendFileSync5, closeSync, existsSync as existsSync13, mkdirSync as mkdirSync13, openSync, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "node:fs";
|
|
5119
|
+
import { dirname as dirname10, join as join11 } from "node:path";
|
|
3837
5120
|
import { fileURLToPath } from "node:url";
|
|
3838
5121
|
|
|
3839
5122
|
// src/usage/token.ts
|
|
@@ -3864,9 +5147,9 @@ function readFromCredentialsFile() {
|
|
|
3864
5147
|
join(homedir(), ".claude", ".credentials.json"),
|
|
3865
5148
|
join(homedir(), ".config", "claude", "credentials.json")
|
|
3866
5149
|
];
|
|
3867
|
-
for (const
|
|
5150
|
+
for (const path7 of candidates) {
|
|
3868
5151
|
try {
|
|
3869
|
-
const blob = readFileSync(
|
|
5152
|
+
const blob = readFileSync(path7, "utf8");
|
|
3870
5153
|
const creds = extractCredentials(blob);
|
|
3871
5154
|
if (creds) return creds;
|
|
3872
5155
|
} catch {
|
|
@@ -4287,16 +5570,12 @@ function bucketToRollup(b) {
|
|
|
4287
5570
|
};
|
|
4288
5571
|
}
|
|
4289
5572
|
function buildRollupsForRange(sessions, sinceDay) {
|
|
4290
|
-
const buckets = dailyActivity(sessions);
|
|
4291
5573
|
const startCounts = /* @__PURE__ */ new Map();
|
|
4292
5574
|
for (const s of sessions) {
|
|
4293
5575
|
const d = sessionDay(s);
|
|
4294
5576
|
if (d) startCounts.set(d, (startCounts.get(d) ?? 0) + 1);
|
|
4295
5577
|
}
|
|
4296
|
-
return
|
|
4297
|
-
...bucketToRollup(b),
|
|
4298
|
-
sessions: startCounts.get(b.date) ?? 0
|
|
4299
|
-
}));
|
|
5578
|
+
return dailyActivity(sessions).filter((b) => !sinceDay || b.date >= sinceDay).map((b) => ({ ...bucketToRollup(b), uniqueSessions: startCounts.get(b.date) ?? 0 }));
|
|
4300
5579
|
}
|
|
4301
5580
|
function dayBoundsMs(day) {
|
|
4302
5581
|
const [y, m, d] = day.split("-").map(Number);
|
|
@@ -4322,7 +5601,7 @@ function sessionTouchesDay(s, day) {
|
|
|
4322
5601
|
}
|
|
4323
5602
|
return sessionDay(s) === day;
|
|
4324
5603
|
}
|
|
4325
|
-
function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
5604
|
+
function buildRichRollupBlocks(day, daySessions, entries, privateProjects, resolveRepo) {
|
|
4326
5605
|
const bounds = dayBoundsMs(day);
|
|
4327
5606
|
const clippedSessions = [];
|
|
4328
5607
|
for (const s of daySessions) {
|
|
@@ -4332,16 +5611,40 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4332
5611
|
}
|
|
4333
5612
|
const bursts = computeBurstsFromSessions(clippedSessions);
|
|
4334
5613
|
const stats = summarizeBursts(bursts);
|
|
5614
|
+
const repoForEntry = (e) => {
|
|
5615
|
+
if (resolveRepo) {
|
|
5616
|
+
const own = resolveRepo(e.project);
|
|
5617
|
+
if (own) return own;
|
|
5618
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5619
|
+
for (const d of e.edited_dirs ?? []) {
|
|
5620
|
+
const r = resolveRepo(d);
|
|
5621
|
+
if (r) counts.set(r, (counts.get(r) ?? 0) + 1);
|
|
5622
|
+
}
|
|
5623
|
+
const dominant = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
5624
|
+
if (dominant) return dominant;
|
|
5625
|
+
}
|
|
5626
|
+
return e.github_repos?.length === 1 ? e.github_repos[0] : null;
|
|
5627
|
+
};
|
|
5628
|
+
const sessionRepo = /* @__PURE__ */ new Map();
|
|
5629
|
+
for (const e of entries) {
|
|
5630
|
+
if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
|
|
5631
|
+
const r = repoForEntry(e);
|
|
5632
|
+
if (r) sessionRepo.set(e.session_id, r);
|
|
5633
|
+
}
|
|
4335
5634
|
const projects = /* @__PURE__ */ new Map();
|
|
4336
5635
|
for (const s of clippedSessions) {
|
|
4337
|
-
const
|
|
4338
|
-
|
|
5636
|
+
const canonical = canonicalProjectName(s.projectName);
|
|
5637
|
+
const name = projectRepoName(s.projectName);
|
|
5638
|
+
if (privateProjects.has(name) || privateProjects.has(canonical)) continue;
|
|
5639
|
+
const repo = resolveRepo?.(canonical) ?? sessionRepo.get(s.id);
|
|
5640
|
+
const key = repo ?? name;
|
|
4339
5641
|
const ms = s.activeSegments.reduce((sum, seg) => sum + (seg.endMs - seg.startMs), 0);
|
|
4340
|
-
const cur = projects.get(
|
|
5642
|
+
const cur = projects.get(key) ?? { project: name, agentTimeMs: 0, sessions: 0, ...repo ? { resolved: repo } : {} };
|
|
4341
5643
|
cur.agentTimeMs += ms;
|
|
4342
5644
|
cur.sessions += 1;
|
|
4343
|
-
projects.set(
|
|
5645
|
+
projects.set(key, cur);
|
|
4344
5646
|
}
|
|
5647
|
+
const projectRepos = /* @__PURE__ */ new Map();
|
|
4345
5648
|
const workingShapes = /* @__PURE__ */ new Map();
|
|
4346
5649
|
const skills = /* @__PURE__ */ new Map();
|
|
4347
5650
|
const subagents = /* @__PURE__ */ new Map();
|
|
@@ -4355,12 +5658,12 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4355
5658
|
let longTotalMin = 0;
|
|
4356
5659
|
let longMaxSingleMin = 0;
|
|
4357
5660
|
for (const e of entries) {
|
|
4358
|
-
if (privateProjects.has(e.project)) continue;
|
|
5661
|
+
if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
|
|
4359
5662
|
const shape = e.signals?.working_shape ?? null;
|
|
4360
5663
|
if (shape) {
|
|
4361
5664
|
const cur = workingShapes.get(shape) ?? { sessions: 0, agentTimeMs: 0 };
|
|
4362
5665
|
cur.sessions += 1;
|
|
4363
|
-
cur.agentTimeMs += e.numbers.active_min * 6e4;
|
|
5666
|
+
cur.agentTimeMs += Math.round(e.numbers.active_min * 6e4);
|
|
4364
5667
|
workingShapes.set(shape, cur);
|
|
4365
5668
|
}
|
|
4366
5669
|
for (const [name, count] of Object.entries(e.skills)) {
|
|
@@ -4375,6 +5678,12 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4375
5678
|
prs += e.numbers.prs;
|
|
4376
5679
|
commits += e.numbers.commits;
|
|
4377
5680
|
pushes += e.numbers.pushes;
|
|
5681
|
+
if (e.github_repos?.length) {
|
|
5682
|
+
const key = sessionRepo.get(e.session_id) ?? projectRepoName(e.project);
|
|
5683
|
+
const set = projectRepos.get(key) ?? /* @__PURE__ */ new Set();
|
|
5684
|
+
for (const r of e.github_repos) set.add(r);
|
|
5685
|
+
projectRepos.set(key, set);
|
|
5686
|
+
}
|
|
4378
5687
|
if (e.flags.includes("long_autonomous")) {
|
|
4379
5688
|
longCount += 1;
|
|
4380
5689
|
longTotalMin += e.numbers.active_min;
|
|
@@ -4382,11 +5691,21 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4382
5691
|
}
|
|
4383
5692
|
}
|
|
4384
5693
|
return {
|
|
4385
|
-
projects: Array.from(projects.entries()).map(([
|
|
5694
|
+
projects: Array.from(projects.entries()).map(([key, v]) => {
|
|
5695
|
+
const extras = [...projectRepos.get(key) ?? []].filter((r) => r !== v.resolved);
|
|
5696
|
+
const repos = v.resolved ? [v.resolved, ...extras] : extras;
|
|
5697
|
+
return {
|
|
5698
|
+
project: v.project,
|
|
5699
|
+
agentTimeMs: v.agentTimeMs,
|
|
5700
|
+
sessions: v.sessions,
|
|
5701
|
+
...repos.length ? { githubRepos: repos.slice(0, 5) } : {}
|
|
5702
|
+
};
|
|
5703
|
+
}).sort((a, b) => b.agentTimeMs - a.agentTimeMs),
|
|
4386
5704
|
workingShapes: Array.from(workingShapes.entries()).map(([shape, v]) => ({ shape, ...v })).sort((a, b) => b.sessions - a.sessions),
|
|
4387
5705
|
concurrencyPeak: stats.peakConcurrent,
|
|
4388
5706
|
parallelMinutes: Math.round(stats.totalParallelMs / 6e4),
|
|
4389
|
-
|
|
5707
|
+
// Wire schema requires integer minutes (active_min is a float).
|
|
5708
|
+
longAutonomous: { count: longCount, totalMin: Math.round(longTotalMin), maxSingleMin: Math.round(longMaxSingleMin) },
|
|
4390
5709
|
toolErrors,
|
|
4391
5710
|
skillsLoaded: Array.from(skills.entries()).map(([name, sessions]) => ({ name, sessions })).sort((a, b) => b.sessions - a.sessions),
|
|
4392
5711
|
subagentsDispatched: Array.from(subagents.entries()).map(([type, count]) => ({ type, count })).sort((a, b) => b.count - a.count),
|
|
@@ -4415,10 +5734,10 @@ function buildEnrichedExtras(entries) {
|
|
|
4415
5734
|
}
|
|
4416
5735
|
return { outcomeMix, helpfulnessMix, goalMix };
|
|
4417
5736
|
}
|
|
4418
|
-
function buildRichBlocksForDay(day, daySessions, privateProjects, enrichmentOptIn) {
|
|
5737
|
+
function buildRichBlocksForDay(day, daySessions, privateProjects, enrichmentOptIn, resolveRepo) {
|
|
4419
5738
|
const entries = listEntriesForDay(day);
|
|
4420
5739
|
if (entries.length === 0) return void 0;
|
|
4421
|
-
const rich = buildRichRollupBlocks(day, daySessions, entries, privateProjects);
|
|
5740
|
+
const rich = buildRichRollupBlocks(day, daySessions, entries, privateProjects, resolveRepo);
|
|
4422
5741
|
const enriched = enrichmentOptIn ? buildEnrichedExtras(entries) : void 0;
|
|
4423
5742
|
return enriched ? { rich, enriched } : { rich };
|
|
4424
5743
|
}
|
|
@@ -4427,10 +5746,11 @@ function buildIngestPayload(inputs) {
|
|
|
4427
5746
|
return {
|
|
4428
5747
|
ingestId: randomUUID(),
|
|
4429
5748
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4430
|
-
...richRollup || inputs.enrichedExtras ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
5749
|
+
...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
4431
5750
|
...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
|
|
4432
5751
|
...richRollup ? { richRollup } : {},
|
|
4433
5752
|
...inputs.enrichedExtras ? { enrichedExtras: inputs.enrichedExtras } : {},
|
|
5753
|
+
...inputs.artifactSignals ? { artifactSignals: inputs.artifactSignals } : {},
|
|
4434
5754
|
...inputs.usageSnapshot ? { usageSnapshot: inputs.usageSnapshot } : {},
|
|
4435
5755
|
...inputs.planTier ? { planTier: inputs.planTier } : {},
|
|
4436
5756
|
...inputs.cyclePeaks ? { cyclePeaks: inputs.cyclePeaks } : {}
|
|
@@ -4450,19 +5770,81 @@ async function pushToTeamServer(config, payload) {
|
|
|
4450
5770
|
return { ok: res.ok, status: res.status, body };
|
|
4451
5771
|
}
|
|
4452
5772
|
|
|
5773
|
+
// src/team/git-remote.ts
|
|
5774
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, statSync } from "node:fs";
|
|
5775
|
+
import { dirname as dirname3, isAbsolute, join as join5, resolve } from "node:path";
|
|
5776
|
+
var GITHUB_URL_RE = /github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/;
|
|
5777
|
+
function parseGithubRemote(url) {
|
|
5778
|
+
const m = url.trim().match(GITHUB_URL_RE);
|
|
5779
|
+
return m ? `${m[1]}/${m[2]}`.toLowerCase() : null;
|
|
5780
|
+
}
|
|
5781
|
+
function originUrl(configText) {
|
|
5782
|
+
let inOrigin = false;
|
|
5783
|
+
for (const line of configText.split("\n")) {
|
|
5784
|
+
const t = line.trim();
|
|
5785
|
+
if (t.startsWith("[")) {
|
|
5786
|
+
inOrigin = /^\[remote\s+"origin"\]/.test(t);
|
|
5787
|
+
continue;
|
|
5788
|
+
}
|
|
5789
|
+
if (!inOrigin) continue;
|
|
5790
|
+
const m = t.match(/^url\s*=\s*(.+)$/);
|
|
5791
|
+
if (m) return m[1].trim();
|
|
5792
|
+
}
|
|
5793
|
+
return null;
|
|
5794
|
+
}
|
|
5795
|
+
function gitConfigPathFor(dir) {
|
|
5796
|
+
const dotGit = join5(dir, ".git");
|
|
5797
|
+
const st = statSync(dotGit, { throwIfNoEntry: false });
|
|
5798
|
+
if (!st) return null;
|
|
5799
|
+
if (st.isDirectory()) return join5(dotGit, "config");
|
|
5800
|
+
const m = readFileSync6(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
|
|
5801
|
+
if (!m) return null;
|
|
5802
|
+
const gd = isAbsolute(m[1]) ? m[1] : resolve(dir, m[1]);
|
|
5803
|
+
const commondirFile = join5(gd, "commondir");
|
|
5804
|
+
if (existsSync4(commondirFile)) {
|
|
5805
|
+
const common = readFileSync6(commondirFile, "utf8").trim();
|
|
5806
|
+
return join5(isAbsolute(common) ? common : resolve(gd, common), "config");
|
|
5807
|
+
}
|
|
5808
|
+
return join5(gd, "config");
|
|
5809
|
+
}
|
|
5810
|
+
function createRepoResolver() {
|
|
5811
|
+
const cache = /* @__PURE__ */ new Map();
|
|
5812
|
+
return (dir) => {
|
|
5813
|
+
if (!dir || !isAbsolute(dir)) return null;
|
|
5814
|
+
const hit = cache.get(dir);
|
|
5815
|
+
if (hit !== void 0) return hit;
|
|
5816
|
+
let repo = null;
|
|
5817
|
+
try {
|
|
5818
|
+
for (let d = dir; ; d = dirname3(d)) {
|
|
5819
|
+
const config = gitConfigPathFor(d);
|
|
5820
|
+
if (config && existsSync4(config)) {
|
|
5821
|
+
const url = originUrl(readFileSync6(config, "utf8"));
|
|
5822
|
+
repo = url ? parseGithubRemote(url) : null;
|
|
5823
|
+
break;
|
|
5824
|
+
}
|
|
5825
|
+
if (d === dirname3(d)) break;
|
|
5826
|
+
}
|
|
5827
|
+
} catch {
|
|
5828
|
+
repo = null;
|
|
5829
|
+
}
|
|
5830
|
+
cache.set(dir, repo);
|
|
5831
|
+
return repo;
|
|
5832
|
+
};
|
|
5833
|
+
}
|
|
5834
|
+
|
|
4453
5835
|
// src/team/queue.ts
|
|
4454
5836
|
init_fs();
|
|
4455
|
-
import { readFileSync as
|
|
4456
|
-
import { dirname as
|
|
5837
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, appendFileSync as appendFileSync2, statSync as statSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
5838
|
+
import { dirname as dirname4 } from "node:path";
|
|
4457
5839
|
var QUEUE_PATH = cclensPath("ingest-queue.jsonl");
|
|
4458
5840
|
var MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
4459
5841
|
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
4460
5842
|
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
4461
|
-
mkdirSync5(
|
|
5843
|
+
mkdirSync5(dirname4(queuePath), { recursive: true });
|
|
4462
5844
|
const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4463
5845
|
appendFileSync2(queuePath, JSON.stringify(entry) + "\n", "utf8");
|
|
4464
5846
|
try {
|
|
4465
|
-
const { size } =
|
|
5847
|
+
const { size } = statSync2(queuePath);
|
|
4466
5848
|
if (size > MAX_SIZE_BYTES) {
|
|
4467
5849
|
pruneOldest(queuePath);
|
|
4468
5850
|
}
|
|
@@ -4472,7 +5854,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
|
4472
5854
|
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
4473
5855
|
let lines;
|
|
4474
5856
|
try {
|
|
4475
|
-
lines =
|
|
5857
|
+
lines = readFileSync7(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
4476
5858
|
} catch {
|
|
4477
5859
|
return [];
|
|
4478
5860
|
}
|
|
@@ -4493,7 +5875,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
|
4493
5875
|
function pruneOldest(queuePath) {
|
|
4494
5876
|
let lines;
|
|
4495
5877
|
try {
|
|
4496
|
-
lines =
|
|
5878
|
+
lines = readFileSync7(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
4497
5879
|
} catch {
|
|
4498
5880
|
return;
|
|
4499
5881
|
}
|
|
@@ -4506,8 +5888,8 @@ init_storage();
|
|
|
4506
5888
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4507
5889
|
|
|
4508
5890
|
// src/usage/profile.ts
|
|
4509
|
-
import { existsSync as
|
|
4510
|
-
import { dirname as
|
|
5891
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
5892
|
+
import { dirname as dirname5 } from "node:path";
|
|
4511
5893
|
var PROFILE_ENDPOINT = "https://api.anthropic.com/api/oauth/profile";
|
|
4512
5894
|
var BETA_HEADER2 = "oauth-2025-04-20";
|
|
4513
5895
|
var PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -4550,9 +5932,9 @@ async function fetchProfile(nowMs = Date.now()) {
|
|
|
4550
5932
|
};
|
|
4551
5933
|
}
|
|
4552
5934
|
function readCachedProfile(cachePath) {
|
|
4553
|
-
if (!
|
|
5935
|
+
if (!existsSync5(cachePath)) return null;
|
|
4554
5936
|
try {
|
|
4555
|
-
const raw = JSON.parse(
|
|
5937
|
+
const raw = JSON.parse(readFileSync8(cachePath, "utf8"));
|
|
4556
5938
|
if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
|
|
4557
5939
|
return raw;
|
|
4558
5940
|
} catch {
|
|
@@ -4560,7 +5942,7 @@ function readCachedProfile(cachePath) {
|
|
|
4560
5942
|
}
|
|
4561
5943
|
}
|
|
4562
5944
|
function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
|
|
4563
|
-
mkdirSync6(
|
|
5945
|
+
mkdirSync6(dirname5(cachePath), { recursive: true });
|
|
4564
5946
|
writeFileSync5(
|
|
4565
5947
|
cachePath,
|
|
4566
5948
|
JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
|
|
@@ -4722,12 +6104,12 @@ async function runTeamBackfill(log3 = noopLog, filePath = USAGE_LOG, configOverr
|
|
|
4722
6104
|
// src/team/last-push.ts
|
|
4723
6105
|
init_fs();
|
|
4724
6106
|
import { writeFileSync as writeFileSync6, unlinkSync as unlinkSync2, mkdirSync as mkdirSync7 } from "node:fs";
|
|
4725
|
-
import { join as
|
|
6107
|
+
import { join as join6 } from "node:path";
|
|
4726
6108
|
var LAST_PUSH_FILE = "team-last-push.json";
|
|
4727
6109
|
function write(record, dir) {
|
|
4728
6110
|
const d = dir ?? cclensHome();
|
|
4729
6111
|
mkdirSync7(d, { recursive: true });
|
|
4730
|
-
writeFileSync6(
|
|
6112
|
+
writeFileSync6(join6(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
|
|
4731
6113
|
}
|
|
4732
6114
|
function writeLastPushSuccess(payload, dir) {
|
|
4733
6115
|
write({ pushedAt: (/* @__PURE__ */ new Date()).toISOString(), ok: true, payload }, dir);
|
|
@@ -4753,6 +6135,7 @@ async function dispatchCommand(command, config, log3) {
|
|
|
4753
6135
|
async function runActivityBackfill(command, config, log3) {
|
|
4754
6136
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4755
6137
|
const { toLocalDay: toLocalDay3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
6138
|
+
const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
|
|
4756
6139
|
const days = command.params.days;
|
|
4757
6140
|
const todayMs = Date.now();
|
|
4758
6141
|
const targetDayMs = todayMs - (days - 1) * 24 * 60 * 60 * 1e3;
|
|
@@ -4778,9 +6161,24 @@ async function runActivityBackfill(command, config, log3) {
|
|
|
4778
6161
|
summary: { pushed: 0, fromDay: targetDay }
|
|
4779
6162
|
};
|
|
4780
6163
|
}
|
|
6164
|
+
const privateProjects = new Set(config.privateProjects ?? []);
|
|
6165
|
+
const enrichmentOptIn = !!config.enrichmentOptIn;
|
|
6166
|
+
const resolveRepo = createRepoResolver();
|
|
4781
6167
|
let pushed = 0;
|
|
4782
6168
|
for (const rollup of rollups) {
|
|
4783
|
-
const
|
|
6169
|
+
const daySessions = sessions.filter((s) => sessionTouchesDay(s, rollup.day));
|
|
6170
|
+
const richBlocks = buildRichBlocksForDay(rollup.day, daySessions, privateProjects, enrichmentOptIn, resolveRepo);
|
|
6171
|
+
let artifactSignals = null;
|
|
6172
|
+
try {
|
|
6173
|
+
artifactSignals = probeArtifactSignals2({ day: rollup.day, extraRoots: [process.cwd()] });
|
|
6174
|
+
} catch {
|
|
6175
|
+
}
|
|
6176
|
+
const payload = buildIngestPayload({
|
|
6177
|
+
rollup,
|
|
6178
|
+
richExtras: richBlocks?.rich,
|
|
6179
|
+
enrichedExtras: richBlocks?.enriched,
|
|
6180
|
+
artifactSignals: artifactSignals ?? void 0
|
|
6181
|
+
});
|
|
4784
6182
|
const result = await pushToTeamServer(config, payload);
|
|
4785
6183
|
if (!result.ok) {
|
|
4786
6184
|
return {
|
|
@@ -4906,6 +6304,8 @@ async function runTeamSync(log3 = noopLog2, configOverride, options = {}) {
|
|
|
4906
6304
|
let lastPushedDay;
|
|
4907
6305
|
const privateProjects = new Set(config.privateProjects ?? []);
|
|
4908
6306
|
const enrichmentOptIn = !!config.enrichmentOptIn;
|
|
6307
|
+
const resolveRepo = createRepoResolver();
|
|
6308
|
+
const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
|
|
4909
6309
|
for (let i = 0; i < rollups.length; i++) {
|
|
4910
6310
|
const rollup = rollups[i];
|
|
4911
6311
|
const isLatest = i === rollups.length - 1;
|
|
@@ -4914,12 +6314,22 @@ async function runTeamSync(log3 = noopLog2, configOverride, options = {}) {
|
|
|
4914
6314
|
rollup.day,
|
|
4915
6315
|
daySessions,
|
|
4916
6316
|
privateProjects,
|
|
4917
|
-
enrichmentOptIn
|
|
6317
|
+
enrichmentOptIn,
|
|
6318
|
+
resolveRepo
|
|
4918
6319
|
);
|
|
6320
|
+
let artifactSignals = null;
|
|
6321
|
+
try {
|
|
6322
|
+
artifactSignals = probeArtifactSignals2({
|
|
6323
|
+
day: rollup.day,
|
|
6324
|
+
extraRoots: [process.cwd()]
|
|
6325
|
+
});
|
|
6326
|
+
} catch {
|
|
6327
|
+
}
|
|
4919
6328
|
const payload = buildIngestPayload({
|
|
4920
6329
|
rollup,
|
|
4921
6330
|
richExtras: richBlocks?.rich,
|
|
4922
6331
|
enrichedExtras: richBlocks?.enriched,
|
|
6332
|
+
artifactSignals: artifactSignals ?? void 0,
|
|
4923
6333
|
usageSnapshot: isLatest ? usageSnapshot : void 0,
|
|
4924
6334
|
planTier,
|
|
4925
6335
|
// Same rationale as usageSnapshot — current cycle data only on the
|
|
@@ -5038,8 +6448,8 @@ async function buildCyclePeaksForPush(planTier, loadCurve) {
|
|
|
5038
6448
|
// src/perception/worker.ts
|
|
5039
6449
|
init_dist();
|
|
5040
6450
|
init_fs();
|
|
5041
|
-
import { statSync as
|
|
5042
|
-
import { basename, dirname as
|
|
6451
|
+
import { statSync as statSync4, readFileSync as readFileSync10 } from "node:fs";
|
|
6452
|
+
import { basename, dirname as dirname8 } from "node:path";
|
|
5043
6453
|
|
|
5044
6454
|
// ../entries/dist/signals.js
|
|
5045
6455
|
init_dist();
|
|
@@ -5271,7 +6681,7 @@ function viewEvent(ev) {
|
|
|
5271
6681
|
cwd: rawCwd
|
|
5272
6682
|
};
|
|
5273
6683
|
}
|
|
5274
|
-
var
|
|
6684
|
+
var IDLE_GAP_MS4 = 3 * 60 * 1e3;
|
|
5275
6685
|
var INTERRUPT_RE2 = /\[request interrupted|interrupted by user/i;
|
|
5276
6686
|
var PR_TITLE_RE = /--title\s+["']([^"']+)["']/;
|
|
5277
6687
|
var BASH_CHAIN_SPLIT_RE = /\|\||&&|;|\|/;
|
|
@@ -5383,7 +6793,7 @@ function closeTurn(t, closed, cwd) {
|
|
|
5383
6793
|
let active = 0;
|
|
5384
6794
|
for (let i = 1; i < ts.length; i++) {
|
|
5385
6795
|
const dt = ts[i] - ts[i - 1];
|
|
5386
|
-
if (dt <
|
|
6796
|
+
if (dt < IDLE_GAP_MS4)
|
|
5387
6797
|
active += dt;
|
|
5388
6798
|
}
|
|
5389
6799
|
closed.push({
|
|
@@ -5410,6 +6820,9 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5410
6820
|
const prTitles = [];
|
|
5411
6821
|
let commits = 0;
|
|
5412
6822
|
let pushes = 0;
|
|
6823
|
+
const gitToolUseIds = /* @__PURE__ */ new Set();
|
|
6824
|
+
const githubRepos = /* @__PURE__ */ new Set();
|
|
6825
|
+
const editedDirCounts = /* @__PURE__ */ new Map();
|
|
5413
6826
|
const modelTurns = /* @__PURE__ */ new Map();
|
|
5414
6827
|
let totalToolErrors = 0;
|
|
5415
6828
|
let totalInterrupts = 0;
|
|
@@ -5451,11 +6864,23 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5451
6864
|
} else {
|
|
5452
6865
|
if (Array.isArray(content)) {
|
|
5453
6866
|
for (const c of content) {
|
|
5454
|
-
if (c
|
|
6867
|
+
if (!c || typeof c !== "object" || c.type !== "tool_result")
|
|
6868
|
+
continue;
|
|
6869
|
+
if (c.is_error) {
|
|
5455
6870
|
totalToolErrors++;
|
|
5456
6871
|
if (cur)
|
|
5457
6872
|
cur.toolErrors++;
|
|
5458
6873
|
}
|
|
6874
|
+
const tuId = c.tool_use_id;
|
|
6875
|
+
if (tuId && gitToolUseIds.has(tuId)) {
|
|
6876
|
+
const rc = c.content;
|
|
6877
|
+
const text = typeof rc === "string" ? rc : Array.isArray(rc) ? rc.map((b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : "").join("\n") : "";
|
|
6878
|
+
for (const m of text.matchAll(/(?<![.\w])github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git\b|[/\s"'),]|$)/g)) {
|
|
6879
|
+
if (m[1].toLowerCase() === "user-attachments")
|
|
6880
|
+
continue;
|
|
6881
|
+
githubRepos.add(`${m[1]}/${m[2]}`.toLowerCase());
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
5459
6884
|
}
|
|
5460
6885
|
}
|
|
5461
6886
|
if (cur && tsMs !== void 0) {
|
|
@@ -5511,10 +6936,6 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5511
6936
|
if (name === "Skill") {
|
|
5512
6937
|
const sk = String(ct.input?.skill ?? "unknown");
|
|
5513
6938
|
cur.skills.set(sk, (cur.skills.get(sk) ?? 0) + 1);
|
|
5514
|
-
} else if (name === "ToolSearch") {
|
|
5515
|
-
const q = String(ct.input?.query ?? "");
|
|
5516
|
-
const key = `(ToolSearch: ${trunc(q, 60)})`;
|
|
5517
|
-
cur.skills.set(key, (cur.skills.get(key) ?? 0) + 1);
|
|
5518
6939
|
}
|
|
5519
6940
|
if (name === "Agent") {
|
|
5520
6941
|
const inp = ct.input ?? {};
|
|
@@ -5544,10 +6965,20 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5544
6965
|
commits++;
|
|
5545
6966
|
if (/\bgit\s+push\b/.test(cmd))
|
|
5546
6967
|
pushes++;
|
|
6968
|
+
if (ct.id && /\bgit\s+push\b|\bgh\s+pr\s+/.test(cmd))
|
|
6969
|
+
gitToolUseIds.add(ct.id);
|
|
5547
6970
|
}
|
|
5548
6971
|
if (eventCwd && (name === "Bash" || name === "Edit" || name === "Write" || name === "Read")) {
|
|
5549
6972
|
cwdCounts.set(eventCwd, (cwdCounts.get(eventCwd) ?? 0) + 1);
|
|
5550
6973
|
}
|
|
6974
|
+
if (name === "Edit" || name === "Write" || name === "MultiEdit" || name === "NotebookEdit") {
|
|
6975
|
+
const fp = String(ct.input?.file_path ?? ct.input?.notebook_path ?? "");
|
|
6976
|
+
const slash = fp.lastIndexOf("/");
|
|
6977
|
+
if (slash > 0) {
|
|
6978
|
+
const dir = fp.slice(0, slash);
|
|
6979
|
+
editedDirCounts.set(dir, (editedDirCounts.get(dir) ?? 0) + 1);
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
5551
6982
|
}
|
|
5552
6983
|
}
|
|
5553
6984
|
}
|
|
@@ -5559,7 +6990,7 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5559
6990
|
let activeMs2 = 0;
|
|
5560
6991
|
for (let i = 1; i < tsSorted.length; i++) {
|
|
5561
6992
|
const dt = tsSorted[i] - tsSorted[i - 1];
|
|
5562
|
-
if (dt <
|
|
6993
|
+
if (dt < IDLE_GAP_MS4)
|
|
5563
6994
|
activeMs2 += dt;
|
|
5564
6995
|
}
|
|
5565
6996
|
const tsSortedStrings = dayEvents.map((e) => e.timestamp).filter((t) => !!t).sort();
|
|
@@ -5572,6 +7003,8 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5572
7003
|
prTitles,
|
|
5573
7004
|
commits,
|
|
5574
7005
|
pushes,
|
|
7006
|
+
githubRepos: [...githubRepos].slice(0, 5),
|
|
7007
|
+
editedDirs: [...editedDirCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([dir]) => dir),
|
|
5575
7008
|
modelTurns,
|
|
5576
7009
|
totalToolErrors,
|
|
5577
7010
|
totalInterrupts,
|
|
@@ -5725,6 +7158,8 @@ function buildEntries(sessionDetail) {
|
|
|
5725
7158
|
first_user,
|
|
5726
7159
|
final_agent,
|
|
5727
7160
|
pr_titles: agg.prTitles,
|
|
7161
|
+
...agg.githubRepos.length ? { github_repos: agg.githubRepos } : {},
|
|
7162
|
+
...agg.editedDirs.length ? { edited_dirs: agg.editedDirs } : {},
|
|
5728
7163
|
top_tools,
|
|
5729
7164
|
skills,
|
|
5730
7165
|
subagents,
|
|
@@ -5744,8 +7179,8 @@ function buildEntries(sessionDetail) {
|
|
|
5744
7179
|
|
|
5745
7180
|
// src/perception/state.ts
|
|
5746
7181
|
init_fs();
|
|
5747
|
-
import { existsSync as
|
|
5748
|
-
import { dirname as
|
|
7182
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, renameSync as renameSync3 } from "node:fs";
|
|
7183
|
+
import { dirname as dirname7 } from "node:path";
|
|
5749
7184
|
var STALE_MS = 15 * 60 * 1e3;
|
|
5750
7185
|
var pathCached = null;
|
|
5751
7186
|
function statePath() {
|
|
@@ -5755,7 +7190,7 @@ function statePath() {
|
|
|
5755
7190
|
}
|
|
5756
7191
|
function readState() {
|
|
5757
7192
|
const p = statePath();
|
|
5758
|
-
if (!
|
|
7193
|
+
if (!existsSync7(p)) {
|
|
5759
7194
|
return {
|
|
5760
7195
|
sweep_in_progress: false,
|
|
5761
7196
|
last_sweep_started_at: null,
|
|
@@ -5763,12 +7198,12 @@ function readState() {
|
|
|
5763
7198
|
file_checkpoints: {}
|
|
5764
7199
|
};
|
|
5765
7200
|
}
|
|
5766
|
-
const raw =
|
|
7201
|
+
const raw = readFileSync9(p, "utf8");
|
|
5767
7202
|
return JSON.parse(raw);
|
|
5768
7203
|
}
|
|
5769
7204
|
function writeState(s) {
|
|
5770
7205
|
const p = statePath();
|
|
5771
|
-
mkdirSync8(
|
|
7206
|
+
mkdirSync8(dirname7(p), { recursive: true });
|
|
5772
7207
|
const tmp = `${p}.tmp`;
|
|
5773
7208
|
writeFileSync7(tmp, JSON.stringify(s, null, 2), "utf8");
|
|
5774
7209
|
renameSync3(tmp, p);
|
|
@@ -5799,18 +7234,18 @@ function updateCheckpoint(jsonlPath, cp) {
|
|
|
5799
7234
|
}
|
|
5800
7235
|
|
|
5801
7236
|
// src/perception/scan.ts
|
|
5802
|
-
import { readdirSync as
|
|
5803
|
-
import { join as
|
|
5804
|
-
import { homedir as
|
|
7237
|
+
import { readdirSync as readdirSync4 } from "node:fs";
|
|
7238
|
+
import { join as join8 } from "node:path";
|
|
7239
|
+
import { homedir as homedir3 } from "node:os";
|
|
5805
7240
|
async function listAllSessionJsonls(root) {
|
|
5806
|
-
const projectsRoot = root ??
|
|
7241
|
+
const projectsRoot = root ?? join8(homedir3(), ".claude", "projects");
|
|
5807
7242
|
const out = [];
|
|
5808
7243
|
try {
|
|
5809
|
-
for (const project of
|
|
5810
|
-
const dir =
|
|
7244
|
+
for (const project of readdirSync4(projectsRoot)) {
|
|
7245
|
+
const dir = join8(projectsRoot, project);
|
|
5811
7246
|
try {
|
|
5812
|
-
for (const f of
|
|
5813
|
-
if (f.endsWith(".jsonl")) out.push(
|
|
7247
|
+
for (const f of readdirSync4(dir)) {
|
|
7248
|
+
if (f.endsWith(".jsonl")) out.push(join8(dir, f));
|
|
5814
7249
|
}
|
|
5815
7250
|
} catch {
|
|
5816
7251
|
}
|
|
@@ -5843,10 +7278,10 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5843
7278
|
const files = await listAllSessionJsonls(opts.projectsRoot);
|
|
5844
7279
|
for (const f of files) {
|
|
5845
7280
|
try {
|
|
5846
|
-
const stat =
|
|
7281
|
+
const stat = statSync4(f);
|
|
5847
7282
|
const prev = state.file_checkpoints[f];
|
|
5848
7283
|
if (prev && prev.byte_offset >= stat.size) continue;
|
|
5849
|
-
const raw =
|
|
7284
|
+
const raw = readFileSync10(f, "utf8");
|
|
5850
7285
|
const rawLines = raw.split("\n").filter(Boolean).map((l) => {
|
|
5851
7286
|
try {
|
|
5852
7287
|
return JSON.parse(l);
|
|
@@ -5857,7 +7292,7 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5857
7292
|
if (rawLines.length === 0) continue;
|
|
5858
7293
|
const { meta, events } = parseTranscript(rawLines);
|
|
5859
7294
|
const fileName = basename(f);
|
|
5860
|
-
const projectDir = basename(
|
|
7295
|
+
const projectDir = basename(dirname8(f));
|
|
5861
7296
|
const sessionId = fileName.replace(/\.jsonl$/, "");
|
|
5862
7297
|
const sd = {
|
|
5863
7298
|
...meta,
|
|
@@ -5896,7 +7331,7 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5896
7331
|
const built = buildEntries(detail);
|
|
5897
7332
|
for (const e of built) {
|
|
5898
7333
|
try {
|
|
5899
|
-
const stat =
|
|
7334
|
+
const stat = statSync4(meta.filePath);
|
|
5900
7335
|
e.source_checkpoint.byte_offset = stat.size;
|
|
5901
7336
|
} catch {
|
|
5902
7337
|
}
|
|
@@ -6398,8 +7833,8 @@ function getErrorMap() {
|
|
|
6398
7833
|
|
|
6399
7834
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
6400
7835
|
var makeIssue = (params) => {
|
|
6401
|
-
const { data, path:
|
|
6402
|
-
const fullPath = [...
|
|
7836
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
7837
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
6403
7838
|
const fullIssue = {
|
|
6404
7839
|
...issueData,
|
|
6405
7840
|
path: fullPath
|
|
@@ -6515,11 +7950,11 @@ var errorUtil;
|
|
|
6515
7950
|
|
|
6516
7951
|
// ../../node_modules/zod/v3/types.js
|
|
6517
7952
|
var ParseInputLazyPath = class {
|
|
6518
|
-
constructor(parent, value,
|
|
7953
|
+
constructor(parent, value, path7, key) {
|
|
6519
7954
|
this._cachedPath = [];
|
|
6520
7955
|
this.parent = parent;
|
|
6521
7956
|
this.data = value;
|
|
6522
|
-
this._path =
|
|
7957
|
+
this._path = path7;
|
|
6523
7958
|
this._key = key;
|
|
6524
7959
|
}
|
|
6525
7960
|
get path() {
|
|
@@ -10053,14 +11488,14 @@ var ENRICHMENT_SYSTEM_PROMPT = SYSTEM_PROMPT;
|
|
|
10053
11488
|
// ../entries/dist/llm-runner.js
|
|
10054
11489
|
init_fs();
|
|
10055
11490
|
import { spawn } from "node:child_process";
|
|
10056
|
-
import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as
|
|
10057
|
-
import { join as
|
|
11491
|
+
import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as existsSync9 } from "node:fs";
|
|
11492
|
+
import { join as join10 } from "node:path";
|
|
10058
11493
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
10059
11494
|
|
|
10060
11495
|
// ../entries/dist/tmux-runner.js
|
|
10061
|
-
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, existsSync as
|
|
10062
|
-
import { join as
|
|
10063
|
-
import { homedir as
|
|
11496
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, existsSync as existsSync8, readdirSync as readdirSync5, realpathSync, readFileSync as readFileSync11, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
|
|
11497
|
+
import { join as join9 } from "node:path";
|
|
11498
|
+
import { homedir as homedir4 } from "node:os";
|
|
10064
11499
|
import { spawnSync } from "node:child_process";
|
|
10065
11500
|
var TmuxUnavailableError = class extends Error {
|
|
10066
11501
|
constructor(message) {
|
|
@@ -10088,16 +11523,16 @@ function tmuxRunnerAvailable() {
|
|
|
10088
11523
|
return { ok: true };
|
|
10089
11524
|
}
|
|
10090
11525
|
function runtimeCwd() {
|
|
10091
|
-
const dir =
|
|
10092
|
-
if (!
|
|
11526
|
+
const dir = join9(homedir4(), ".cclens", "runtime");
|
|
11527
|
+
if (!existsSync8(dir))
|
|
10093
11528
|
mkdirSync9(dir, { recursive: true });
|
|
10094
11529
|
return realpathSync(dir);
|
|
10095
11530
|
}
|
|
10096
11531
|
function ensureRuntimeCwdTrusted(cwd) {
|
|
10097
|
-
const cfgPath =
|
|
11532
|
+
const cfgPath = join9(homedir4(), ".claude.json");
|
|
10098
11533
|
let cfg;
|
|
10099
11534
|
try {
|
|
10100
|
-
cfg = JSON.parse(
|
|
11535
|
+
cfg = JSON.parse(readFileSync11(cfgPath, "utf8"));
|
|
10101
11536
|
} catch {
|
|
10102
11537
|
return;
|
|
10103
11538
|
}
|
|
@@ -10140,9 +11575,9 @@ async function runClaudeUnderTmuxImpl(args) {
|
|
|
10140
11575
|
ensureRuntimeCwdTrusted(cwd);
|
|
10141
11576
|
const runId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
10142
11577
|
const sessionName = `cclens-${runId}`;
|
|
10143
|
-
const systemFile =
|
|
10144
|
-
const userFile =
|
|
10145
|
-
const wrapper =
|
|
11578
|
+
const systemFile = join9(cwd, `system-${runId}.txt`);
|
|
11579
|
+
const userFile = join9(cwd, `user-${runId}.txt`);
|
|
11580
|
+
const wrapper = join9(cwd, `run-${runId}.sh`);
|
|
10146
11581
|
writeFileSync8(systemFile, args.systemPrompt);
|
|
10147
11582
|
writeFileSync8(userFile, args.reminder ? `${args.userPrompt}
|
|
10148
11583
|
|
|
@@ -10221,35 +11656,35 @@ function num(v) {
|
|
|
10221
11656
|
function sleep(ms) {
|
|
10222
11657
|
return new Promise((r) => setTimeout(r, ms));
|
|
10223
11658
|
}
|
|
10224
|
-
var PROJECTS_ROOT = () =>
|
|
11659
|
+
var PROJECTS_ROOT = () => join9(homedir4(), ".claude", "projects");
|
|
10225
11660
|
function snapshotAllTranscripts() {
|
|
10226
11661
|
const out = /* @__PURE__ */ new Set();
|
|
10227
11662
|
const root = PROJECTS_ROOT();
|
|
10228
11663
|
let subs;
|
|
10229
11664
|
try {
|
|
10230
|
-
subs =
|
|
11665
|
+
subs = readdirSync5(root);
|
|
10231
11666
|
} catch {
|
|
10232
11667
|
return out;
|
|
10233
11668
|
}
|
|
10234
11669
|
for (const sub of subs) {
|
|
10235
|
-
const dir =
|
|
11670
|
+
const dir = join9(root, sub);
|
|
10236
11671
|
let files;
|
|
10237
11672
|
try {
|
|
10238
|
-
files =
|
|
11673
|
+
files = readdirSync5(dir);
|
|
10239
11674
|
} catch {
|
|
10240
11675
|
continue;
|
|
10241
11676
|
}
|
|
10242
11677
|
for (const f of files) {
|
|
10243
11678
|
if (f.endsWith(".jsonl"))
|
|
10244
|
-
out.add(
|
|
11679
|
+
out.add(join9(dir, f));
|
|
10245
11680
|
}
|
|
10246
11681
|
}
|
|
10247
11682
|
return out;
|
|
10248
11683
|
}
|
|
10249
|
-
function readJsonlCwd(
|
|
11684
|
+
function readJsonlCwd(path7, maxLines = 8) {
|
|
10250
11685
|
let raw;
|
|
10251
11686
|
try {
|
|
10252
|
-
raw =
|
|
11687
|
+
raw = readFileSync11(path7, "utf8");
|
|
10253
11688
|
} catch {
|
|
10254
11689
|
return void 0;
|
|
10255
11690
|
}
|
|
@@ -10277,22 +11712,22 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
10277
11712
|
const root = PROJECTS_ROOT();
|
|
10278
11713
|
let subs;
|
|
10279
11714
|
try {
|
|
10280
|
-
subs =
|
|
11715
|
+
subs = readdirSync5(root);
|
|
10281
11716
|
} catch {
|
|
10282
11717
|
subs = [];
|
|
10283
11718
|
}
|
|
10284
11719
|
for (const sub of subs) {
|
|
10285
|
-
const dir =
|
|
11720
|
+
const dir = join9(root, sub);
|
|
10286
11721
|
let files;
|
|
10287
11722
|
try {
|
|
10288
|
-
files =
|
|
11723
|
+
files = readdirSync5(dir);
|
|
10289
11724
|
} catch {
|
|
10290
11725
|
continue;
|
|
10291
11726
|
}
|
|
10292
11727
|
for (const f of files) {
|
|
10293
11728
|
if (!f.endsWith(".jsonl"))
|
|
10294
11729
|
continue;
|
|
10295
|
-
const full =
|
|
11730
|
+
const full = join9(dir, f);
|
|
10296
11731
|
if (existingBefore.has(full))
|
|
10297
11732
|
continue;
|
|
10298
11733
|
if (readJsonlCwd(full) === targetCwd)
|
|
@@ -10303,10 +11738,10 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
10303
11738
|
}
|
|
10304
11739
|
throw new TmuxRunError(`timeout waiting for claude to create the session transcript (cwd: ${targetCwd})`);
|
|
10305
11740
|
}
|
|
10306
|
-
function parseTranscript2(
|
|
11741
|
+
function parseTranscript2(path7, defaultModel) {
|
|
10307
11742
|
let raw;
|
|
10308
11743
|
try {
|
|
10309
|
-
raw =
|
|
11744
|
+
raw = readFileSync11(path7, "utf8");
|
|
10310
11745
|
} catch {
|
|
10311
11746
|
return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
|
|
10312
11747
|
}
|
|
@@ -10366,7 +11801,7 @@ function cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath) {
|
|
|
10366
11801
|
}
|
|
10367
11802
|
for (const f of [`system-${runId}.txt`, `user-${runId}.txt`, `run-${runId}.sh`]) {
|
|
10368
11803
|
try {
|
|
10369
|
-
unlinkSync3(
|
|
11804
|
+
unlinkSync3(join9(cwd, f));
|
|
10370
11805
|
} catch {
|
|
10371
11806
|
}
|
|
10372
11807
|
}
|
|
@@ -10381,7 +11816,7 @@ function shellEscape(s) {
|
|
|
10381
11816
|
// ../entries/dist/llm-runner.js
|
|
10382
11817
|
var RUNS_DIR = cclensPath("llm-runs");
|
|
10383
11818
|
function ensureRunsDir() {
|
|
10384
|
-
if (!
|
|
11819
|
+
if (!existsSync9(RUNS_DIR)) {
|
|
10385
11820
|
try {
|
|
10386
11821
|
mkdirSync10(RUNS_DIR, { recursive: true });
|
|
10387
11822
|
} catch {
|
|
@@ -10410,17 +11845,17 @@ function newRunId(kind) {
|
|
|
10410
11845
|
return `${ts}_${kind}_${short}`;
|
|
10411
11846
|
}
|
|
10412
11847
|
function tracePath(runId) {
|
|
10413
|
-
return
|
|
11848
|
+
return join10(RUNS_DIR, `${runId}.jsonl`);
|
|
10414
11849
|
}
|
|
10415
|
-
function safeAppend(
|
|
11850
|
+
function safeAppend(path7, line) {
|
|
10416
11851
|
try {
|
|
10417
|
-
appendFileSync3(
|
|
11852
|
+
appendFileSync3(path7, line);
|
|
10418
11853
|
} catch {
|
|
10419
11854
|
}
|
|
10420
11855
|
}
|
|
10421
|
-
function safeWrite(
|
|
11856
|
+
function safeWrite(path7, line) {
|
|
10422
11857
|
try {
|
|
10423
|
-
writeFileSync9(
|
|
11858
|
+
writeFileSync9(path7, line);
|
|
10424
11859
|
} catch {
|
|
10425
11860
|
}
|
|
10426
11861
|
}
|
|
@@ -10498,7 +11933,7 @@ async function runClaudeSubprocess(args) {
|
|
|
10498
11933
|
return runClaudePrintMode(args);
|
|
10499
11934
|
}
|
|
10500
11935
|
function runClaudePrintMode(args) {
|
|
10501
|
-
return new Promise((
|
|
11936
|
+
return new Promise((resolve3, reject) => {
|
|
10502
11937
|
ensureRunsDir();
|
|
10503
11938
|
const kind = detectKindFromSystemPrompt(args.systemPrompt);
|
|
10504
11939
|
const runId = newRunId(kind);
|
|
@@ -10629,7 +12064,7 @@ ${args.reminder}` : args.userPrompt;
|
|
|
10629
12064
|
reject(new Error(`claude exited ${code}: ${stderr.trim().slice(0, 300)}`));
|
|
10630
12065
|
return;
|
|
10631
12066
|
}
|
|
10632
|
-
|
|
12067
|
+
resolve3({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
|
|
10633
12068
|
});
|
|
10634
12069
|
proc.on("error", (err) => {
|
|
10635
12070
|
safeAppend(trace, JSON.stringify({ _meta: { type: "spawn_error", run_id: runId, ts: (/* @__PURE__ */ new Date()).toISOString(), error: err.message } }) + "\n");
|
|
@@ -10809,8 +12244,8 @@ function applyEnrichmentError(entry, errorMessage, model, costUsd, generatedAt,
|
|
|
10809
12244
|
|
|
10810
12245
|
// ../entries/dist/budget.js
|
|
10811
12246
|
init_fs();
|
|
10812
|
-
import { appendFileSync as appendFileSync4, readFileSync as
|
|
10813
|
-
import { dirname as
|
|
12247
|
+
import { appendFileSync as appendFileSync4, readFileSync as readFileSync12, existsSync as existsSync10, mkdirSync as mkdirSync11 } from "node:fs";
|
|
12248
|
+
import { dirname as dirname9 } from "node:path";
|
|
10814
12249
|
var spendPathCached = null;
|
|
10815
12250
|
function spendPath() {
|
|
10816
12251
|
if (spendPathCached)
|
|
@@ -10820,17 +12255,17 @@ function spendPath() {
|
|
|
10820
12255
|
}
|
|
10821
12256
|
function appendSpend(record) {
|
|
10822
12257
|
const p = spendPath();
|
|
10823
|
-
mkdirSync11(
|
|
12258
|
+
mkdirSync11(dirname9(p), { recursive: true });
|
|
10824
12259
|
appendFileSync4(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
|
|
10825
12260
|
}
|
|
10826
12261
|
function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
10827
12262
|
const p = spendPath();
|
|
10828
|
-
if (!
|
|
12263
|
+
if (!existsSync10(p))
|
|
10829
12264
|
return 0;
|
|
10830
12265
|
const year = now.getUTCFullYear();
|
|
10831
12266
|
const month = now.getUTCMonth();
|
|
10832
12267
|
let total = 0;
|
|
10833
|
-
const raw =
|
|
12268
|
+
const raw = readFileSync12(p, "utf8");
|
|
10834
12269
|
for (const line of raw.split("\n")) {
|
|
10835
12270
|
if (!line)
|
|
10836
12271
|
continue;
|
|
@@ -10852,7 +12287,7 @@ function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
|
10852
12287
|
|
|
10853
12288
|
// ../entries/dist/pipeline-lock.js
|
|
10854
12289
|
init_fs();
|
|
10855
|
-
import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as
|
|
12290
|
+
import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync11, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
|
|
10856
12291
|
var STALE_MS2 = 60 * 1e3;
|
|
10857
12292
|
var HEARTBEAT_MS = 30 * 1e3;
|
|
10858
12293
|
var lockPathCached = null;
|
|
@@ -10898,13 +12333,13 @@ function pidAlive(pid) {
|
|
|
10898
12333
|
}
|
|
10899
12334
|
function interactiveLockFresh(nowMs) {
|
|
10900
12335
|
const p = lockPath();
|
|
10901
|
-
if (!
|
|
12336
|
+
if (!existsSync11(p))
|
|
10902
12337
|
return false;
|
|
10903
12338
|
try {
|
|
10904
|
-
const mtime =
|
|
12339
|
+
const mtime = statSync5(p).mtimeMs;
|
|
10905
12340
|
if (nowMs - mtime > STALE_MS2)
|
|
10906
12341
|
return false;
|
|
10907
|
-
const pid = Number(
|
|
12342
|
+
const pid = Number(readFileSync13(p, "utf8").trim());
|
|
10908
12343
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
10909
12344
|
return false;
|
|
10910
12345
|
if (!pidAlive(pid))
|
|
@@ -10919,7 +12354,7 @@ function interactiveLockFresh(nowMs) {
|
|
|
10919
12354
|
var THIRTY_MIN_MS = 30 * 60 * 1e3;
|
|
10920
12355
|
|
|
10921
12356
|
// ../entries/dist/settings.js
|
|
10922
|
-
import { readFileSync as
|
|
12357
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync12, existsSync as existsSync12 } from "node:fs";
|
|
10923
12358
|
init_fs();
|
|
10924
12359
|
var DEFAULT_SETTINGS = {
|
|
10925
12360
|
ai_features: {
|
|
@@ -10951,10 +12386,10 @@ function fromDisk(d) {
|
|
|
10951
12386
|
}
|
|
10952
12387
|
function readSettings() {
|
|
10953
12388
|
const p = settingsPath();
|
|
10954
|
-
if (!
|
|
12389
|
+
if (!existsSync12(p))
|
|
10955
12390
|
return DEFAULT_SETTINGS;
|
|
10956
12391
|
try {
|
|
10957
|
-
const raw =
|
|
12392
|
+
const raw = readFileSync14(p, "utf8");
|
|
10958
12393
|
return fromDisk(JSON.parse(raw));
|
|
10959
12394
|
} catch {
|
|
10960
12395
|
return DEFAULT_SETTINGS;
|
|
@@ -11127,7 +12562,7 @@ function rollupOutcomeDay(entries) {
|
|
|
11127
12562
|
return "exploratory";
|
|
11128
12563
|
return "trivial";
|
|
11129
12564
|
}
|
|
11130
|
-
function
|
|
12565
|
+
function truncate5(s, max) {
|
|
11131
12566
|
if (s.length <= max)
|
|
11132
12567
|
return s;
|
|
11133
12568
|
return s.slice(0, max - 1).trimEnd() + "\u2026";
|
|
@@ -11183,7 +12618,7 @@ function computeDaySignals(entries) {
|
|
|
11183
12618
|
type,
|
|
11184
12619
|
count: v.count,
|
|
11185
12620
|
sample_description: v.sample_description,
|
|
11186
|
-
sample_prompt_preview:
|
|
12621
|
+
sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
|
|
11187
12622
|
}));
|
|
11188
12623
|
const frameCounts = /* @__PURE__ */ new Map();
|
|
11189
12624
|
for (const s of signalsList) {
|
|
@@ -11202,7 +12637,7 @@ function computeDaySignals(entries) {
|
|
|
11202
12637
|
if ((e.first_user ?? "").length > 0)
|
|
11203
12638
|
verbosity_distribution[s.verbosity] += 1;
|
|
11204
12639
|
for (const ref of s.external_refs) {
|
|
11205
|
-
external_refs.push({ session_id: e.session_id, kind: ref.kind, preview:
|
|
12640
|
+
external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate5(ref.preview, 200) });
|
|
11206
12641
|
}
|
|
11207
12642
|
const ints = e.numbers.interrupts ?? 0;
|
|
11208
12643
|
interrupts += ints;
|
|
@@ -12045,7 +13480,7 @@ function computeInteractionModes(entries) {
|
|
|
12045
13480
|
date: entry.local_day,
|
|
12046
13481
|
project_display: prettyProject3(entry.project),
|
|
12047
13482
|
type: sa.type,
|
|
12048
|
-
prompt_preview:
|
|
13483
|
+
prompt_preview: truncate6(sa.prompt_preview, 200)
|
|
12049
13484
|
});
|
|
12050
13485
|
}
|
|
12051
13486
|
const skillExamples = [];
|
|
@@ -12062,7 +13497,7 @@ function computeInteractionModes(entries) {
|
|
|
12062
13497
|
skillExamples.push({
|
|
12063
13498
|
date: e.local_day,
|
|
12064
13499
|
skill,
|
|
12065
|
-
first_user_preview:
|
|
13500
|
+
first_user_preview: truncate6(e.first_user, 200)
|
|
12066
13501
|
});
|
|
12067
13502
|
}
|
|
12068
13503
|
}
|
|
@@ -12079,7 +13514,7 @@ function computeInteractionModes(entries) {
|
|
|
12079
13514
|
project_display: prettyProject3(longestTurnEntry.project),
|
|
12080
13515
|
active_min: longestTurnEntry.numbers.active_min,
|
|
12081
13516
|
top_tools: longestTurnEntry.top_tools.slice(0, 5),
|
|
12082
|
-
first_user_preview:
|
|
13517
|
+
first_user_preview: truncate6(longestTurnEntry.first_user, 200)
|
|
12083
13518
|
} : null;
|
|
12084
13519
|
const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
|
|
12085
13520
|
const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
|
|
@@ -12110,7 +13545,7 @@ function computeInteractionModes(entries) {
|
|
|
12110
13545
|
}
|
|
12111
13546
|
};
|
|
12112
13547
|
}
|
|
12113
|
-
function
|
|
13548
|
+
function truncate6(s, max) {
|
|
12114
13549
|
if (s.length <= max)
|
|
12115
13550
|
return s;
|
|
12116
13551
|
return s.slice(0, max - 1).trimEnd() + "\u2026";
|
|
@@ -12167,7 +13602,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
|
|
|
12167
13602
|
evidence_subagent = {
|
|
12168
13603
|
type: sa.type,
|
|
12169
13604
|
description: sa.description,
|
|
12170
|
-
prompt_preview:
|
|
13605
|
+
prompt_preview: truncate6(sa.prompt_preview, 200)
|
|
12171
13606
|
};
|
|
12172
13607
|
}
|
|
12173
13608
|
const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
|
|
@@ -12178,7 +13613,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
|
|
|
12178
13613
|
outcome: dayOutcome.get(dd.key) ?? null,
|
|
12179
13614
|
helpfulness: dayHelp.get(dd.key) ?? null,
|
|
12180
13615
|
evidence_subagent,
|
|
12181
|
-
evidence_first_user: repEntry?.first_user ?
|
|
13616
|
+
evidence_first_user: repEntry?.first_user ? truncate6(repEntry.first_user, 200) : null,
|
|
12182
13617
|
day_signature: dd.day_signature ?? null
|
|
12183
13618
|
};
|
|
12184
13619
|
});
|
|
@@ -12253,7 +13688,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
|
|
|
12253
13688
|
date: day,
|
|
12254
13689
|
session_id: ref.session_id,
|
|
12255
13690
|
ref_kind: ref.kind,
|
|
12256
|
-
preview:
|
|
13691
|
+
preview: truncate6(ref.preview, 200)
|
|
12257
13692
|
});
|
|
12258
13693
|
}
|
|
12259
13694
|
total_interrupts += signals.comm_style.steering.interrupts;
|
|
@@ -12325,7 +13760,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
|
|
|
12325
13760
|
count: v.count,
|
|
12326
13761
|
days: [...v.days].sort(),
|
|
12327
13762
|
sample_description: v.sample_description,
|
|
12328
|
-
sample_prompt_preview:
|
|
13763
|
+
sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
|
|
12329
13764
|
})),
|
|
12330
13765
|
threads,
|
|
12331
13766
|
communication_style: {
|
|
@@ -12625,7 +14060,7 @@ var MonthDigestResponseSchema = external_exports.object({
|
|
|
12625
14060
|
}).passthrough();
|
|
12626
14061
|
|
|
12627
14062
|
// ../entries/dist/top-sessions.js
|
|
12628
|
-
var
|
|
14063
|
+
var IDLE_GAP_MS5 = 3 * 60 * 1e3;
|
|
12629
14064
|
var LONG_AUTONOMOUS_MIN = 20;
|
|
12630
14065
|
var N_USER = 150;
|
|
12631
14066
|
var N_FIRST_AGENT = 150;
|
|
@@ -12656,7 +14091,7 @@ function activeMs(timestamps) {
|
|
|
12656
14091
|
let active = 0;
|
|
12657
14092
|
for (let i = 1; i < ts.length; i++) {
|
|
12658
14093
|
const dt = ts[i] - ts[i - 1];
|
|
12659
|
-
if (dt <
|
|
14094
|
+
if (dt < IDLE_GAP_MS5)
|
|
12660
14095
|
active += dt;
|
|
12661
14096
|
}
|
|
12662
14097
|
return active;
|
|
@@ -12830,7 +14265,7 @@ function buildSessionSlice(entry, events, daySignature) {
|
|
|
12830
14265
|
let intEnd = sortedTs[0];
|
|
12831
14266
|
for (let i = 1; i < sortedTs.length; i++) {
|
|
12832
14267
|
const dt = sortedTs[i] - intEnd;
|
|
12833
|
-
if (dt >=
|
|
14268
|
+
if (dt >= IDLE_GAP_MS5) {
|
|
12834
14269
|
intervals.push({
|
|
12835
14270
|
start_min: fmtMin(intStart - sliceStartMs),
|
|
12836
14271
|
end_min: fmtMin(intEnd - sliceStartMs)
|
|
@@ -13711,14 +15146,14 @@ async function getUpdateAvailability() {
|
|
|
13711
15146
|
if (isDevMode()) return null;
|
|
13712
15147
|
const latest = await fetchLatestVersion();
|
|
13713
15148
|
if (latest === null) return {
|
|
13714
|
-
current: "0.
|
|
15149
|
+
current: "0.12.1",
|
|
13715
15150
|
latest: null,
|
|
13716
15151
|
updateAvailable: false
|
|
13717
15152
|
};
|
|
13718
15153
|
return {
|
|
13719
|
-
current: "0.
|
|
15154
|
+
current: "0.12.1",
|
|
13720
15155
|
latest,
|
|
13721
|
-
updateAvailable: shouldUpdate("0.
|
|
15156
|
+
updateAvailable: shouldUpdate("0.12.1", latest)
|
|
13722
15157
|
};
|
|
13723
15158
|
}
|
|
13724
15159
|
|
|
@@ -13728,7 +15163,7 @@ var DAEMON_LOG = cclensPath("daemon.log");
|
|
|
13728
15163
|
var UPDATE_STATE = cclensPath("daemon-update.json");
|
|
13729
15164
|
var WATCHDOG_INTERVAL_MS = 5 * 1e3;
|
|
13730
15165
|
var AUTO_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
13731
|
-
mkdirSync13(
|
|
15166
|
+
mkdirSync13(dirname10(USAGE_LOG3), { recursive: true });
|
|
13732
15167
|
function log2(level, message) {
|
|
13733
15168
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${level.toUpperCase()} ${message}
|
|
13734
15169
|
`;
|
|
@@ -13770,7 +15205,7 @@ var perceptionHandle = setInterval(async () => {
|
|
|
13770
15205
|
}, PERCEPTION_INTERVAL_MS);
|
|
13771
15206
|
function readUpdateState() {
|
|
13772
15207
|
try {
|
|
13773
|
-
return JSON.parse(
|
|
15208
|
+
return JSON.parse(readFileSync15(UPDATE_STATE, "utf8"));
|
|
13774
15209
|
} catch {
|
|
13775
15210
|
return null;
|
|
13776
15211
|
}
|
|
@@ -13790,7 +15225,7 @@ function nextUpdateCheckFromState(nowMs) {
|
|
|
13790
15225
|
}
|
|
13791
15226
|
var nextUpdateCheckAtMs = nextUpdateCheckFromState(Date.now());
|
|
13792
15227
|
function cliEntryPath() {
|
|
13793
|
-
return
|
|
15228
|
+
return join11(dirname10(fileURLToPath(import.meta.url)), "index.js");
|
|
13794
15229
|
}
|
|
13795
15230
|
async function runDaemonUpdateCheck() {
|
|
13796
15231
|
if (process.env.FLEETLENS_DAEMON_AUTO_UPDATE === "0") {
|
|
@@ -13819,7 +15254,7 @@ async function runDaemonUpdateCheck() {
|
|
|
13819
15254
|
return;
|
|
13820
15255
|
}
|
|
13821
15256
|
const entry = cliEntryPath();
|
|
13822
|
-
if (!
|
|
15257
|
+
if (!existsSync13(entry)) {
|
|
13823
15258
|
log2("warn", `update check found ${availability.latest}, but CLI entry is missing at ${entry}`);
|
|
13824
15259
|
return;
|
|
13825
15260
|
}
|
|
@@ -13911,7 +15346,7 @@ function scheduleAfter(now, outcome) {
|
|
|
13911
15346
|
nextPollAtMs = now + currentIntervalMs;
|
|
13912
15347
|
}
|
|
13913
15348
|
function sleep2(ms) {
|
|
13914
|
-
return new Promise((
|
|
15349
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
13915
15350
|
}
|
|
13916
15351
|
async function runLoop() {
|
|
13917
15352
|
while (true) {
|