fleetlens 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.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.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +1 -1
- 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 +1 -1
- 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.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/week/[startDate]/route.js +1 -1
- 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.nft.json +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.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.nft.json +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.nft.json +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.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.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.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.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.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.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.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.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.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.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 +18 -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.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.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.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.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.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.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.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.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_04rh1zd._.js +1 -1
- package/app/apps/web/.next/server/chunks/packages_parser_dist_0ndsxe6._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0_xpuh7._.js → [root-of-the-server]__03y~03u._.js} +2 -2
- 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]__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_0af94gl._.js +1 -1
- 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/WH20Ct_NdpZTKsqI_yquG/_clientMiddlewareManifest.js +6 -0
- package/app/apps/web/.next/static/chunks/00xkqnvk4-d1-.js +10 -0
- package/app/apps/web/.next/static/chunks/0716x58e1_2c5.js +1 -0
- package/app/apps/web/.next/static/chunks/{0s4eyofh28l~u.js → 0ck03i0l4zeun.js} +1 -1
- 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/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 +1592 -252
- package/dist/index.js +1495 -168
- package/package.json +1 -1
- 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/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/0uev~g~qvbjv9.js +0 -4
- package/app/apps/web/.next/static/m6ibRSdAu8jD10VBA2OFH/_clientMiddlewareManifest.js +0 -1
- /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → WH20Ct_NdpZTKsqI_yquG}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{m6ibRSdAu8jD10VBA2OFH → WH20Ct_NdpZTKsqI_yquG}/_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,
|
|
@@ -517,13 +538,13 @@ function summarizeBursts(bursts) {
|
|
|
517
538
|
function groupByProject(sessions) {
|
|
518
539
|
const map = /* @__PURE__ */ new Map();
|
|
519
540
|
for (const s of sessions) {
|
|
520
|
-
const
|
|
521
|
-
const key =
|
|
541
|
+
const repo = projectRepoName(s.projectName);
|
|
542
|
+
const key = repo;
|
|
522
543
|
let cur = map.get(key);
|
|
523
544
|
if (!cur) {
|
|
524
545
|
cur = {
|
|
525
|
-
projectDir:
|
|
526
|
-
projectName:
|
|
546
|
+
projectDir: repo,
|
|
547
|
+
projectName: repo,
|
|
527
548
|
sessions: [],
|
|
528
549
|
rawProjectDirs: [],
|
|
529
550
|
worktreeCount: 0,
|
|
@@ -565,7 +586,7 @@ function groupByProject(sessions) {
|
|
|
565
586
|
}
|
|
566
587
|
return Array.from(map.values()).sort((a, b) => (b.lastActiveMs ?? 0) - (a.lastActiveMs ?? 0));
|
|
567
588
|
}
|
|
568
|
-
var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
|
|
589
|
+
var BLANK_USAGE, WORKTREE_MARKERS, CONDUCTOR_RE, SUPERSET_MARKER, UUID_SEG_RE, PR_CREATE_RE, PR_NUMBER_RE, TITLE_FLAG_RE;
|
|
569
590
|
var init_analytics = __esm({
|
|
570
591
|
"../parser/dist/analytics.js"() {
|
|
571
592
|
"use strict";
|
|
@@ -576,6 +597,8 @@ var init_analytics = __esm({
|
|
|
576
597
|
"/claude/worktrees/"
|
|
577
598
|
];
|
|
578
599
|
CONDUCTOR_RE = /\/conductor\/workspaces\/[^/]+\/([^/]+)(?:\/|$)/;
|
|
600
|
+
SUPERSET_MARKER = "/.superset/worktrees/";
|
|
601
|
+
UUID_SEG_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
579
602
|
PR_CREATE_RE = /gh\s+pr\s+create\b/i;
|
|
580
603
|
PR_NUMBER_RE = /#(\d+)/;
|
|
581
604
|
TITLE_FLAG_RE = /--title\s+["']([^"']+)["']/;
|
|
@@ -589,7 +612,7 @@ function getAgentMetadata(kind) {
|
|
|
589
612
|
function isAgentKind(s) {
|
|
590
613
|
return typeof s === "string" && KNOWN_AGENT_KINDS.has(s);
|
|
591
614
|
}
|
|
592
|
-
var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
|
|
615
|
+
var CLAUDE_CODE_METADATA, CODEX_METADATA, GEMINI_METADATA, ANTIGRAVITY_METADATA, COWORK_METADATA, agentMetadata, KNOWN_AGENT_KINDS;
|
|
593
616
|
var init_agent_metadata = __esm({
|
|
594
617
|
"../parser/dist/agent-metadata.js"() {
|
|
595
618
|
"use strict";
|
|
@@ -614,10 +637,26 @@ var init_agent_metadata = __esm({
|
|
|
614
637
|
accentColor: "rgb(124, 92, 246)",
|
|
615
638
|
iconChar: "\u273A"
|
|
616
639
|
};
|
|
640
|
+
ANTIGRAVITY_METADATA = {
|
|
641
|
+
kind: "antigravity",
|
|
642
|
+
displayName: "Antigravity",
|
|
643
|
+
shortLabel: "Agy",
|
|
644
|
+
accentColor: "rgb(236, 72, 153)",
|
|
645
|
+
iconChar: "\u23C3"
|
|
646
|
+
};
|
|
647
|
+
COWORK_METADATA = {
|
|
648
|
+
kind: "cowork",
|
|
649
|
+
displayName: "Cowork",
|
|
650
|
+
shortLabel: "Cowork",
|
|
651
|
+
accentColor: "rgb(217, 119, 87)",
|
|
652
|
+
iconChar: "\u2318"
|
|
653
|
+
};
|
|
617
654
|
agentMetadata = [
|
|
618
655
|
CLAUDE_CODE_METADATA,
|
|
619
656
|
CODEX_METADATA,
|
|
620
|
-
GEMINI_METADATA
|
|
657
|
+
GEMINI_METADATA,
|
|
658
|
+
ANTIGRAVITY_METADATA,
|
|
659
|
+
COWORK_METADATA
|
|
621
660
|
];
|
|
622
661
|
KNOWN_AGENT_KINDS = new Set(agentMetadata.map((m) => m.kind));
|
|
623
662
|
}
|
|
@@ -1643,6 +1682,52 @@ async function computeSessionUsageWithSubagents(parentLines, projectDirPath, ses
|
|
|
1643
1682
|
}));
|
|
1644
1683
|
return usage;
|
|
1645
1684
|
}
|
|
1685
|
+
async function scanWorkflowAggregate(projectDirPath, sessionId) {
|
|
1686
|
+
const dir = path.join(projectDirPath, sessionId, "workflows");
|
|
1687
|
+
let entries;
|
|
1688
|
+
try {
|
|
1689
|
+
entries = await fs.readdir(dir);
|
|
1690
|
+
} catch {
|
|
1691
|
+
return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
|
|
1692
|
+
}
|
|
1693
|
+
const jsonFiles = entries.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
|
|
1694
|
+
if (jsonFiles.length === 0)
|
|
1695
|
+
return { workflowCount: 0, spawnedAgentCount: 0, spans: [] };
|
|
1696
|
+
let spawnedAgentCount = 0;
|
|
1697
|
+
const spans = [];
|
|
1698
|
+
const parsed = await Promise.all(jsonFiles.map(async (f) => {
|
|
1699
|
+
try {
|
|
1700
|
+
const j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
|
|
1701
|
+
if (typeof j.agentCount === "number")
|
|
1702
|
+
spawnedAgentCount += j.agentCount;
|
|
1703
|
+
if (typeof j.startTime === "number" && typeof j.durationMs === "number" && j.durationMs > 0) {
|
|
1704
|
+
spans.push({ startMs: j.startTime, endMs: j.startTime + j.durationMs });
|
|
1705
|
+
}
|
|
1706
|
+
return true;
|
|
1707
|
+
} catch {
|
|
1708
|
+
return false;
|
|
1709
|
+
}
|
|
1710
|
+
}));
|
|
1711
|
+
return { workflowCount: parsed.filter(Boolean).length, spawnedAgentCount, spans };
|
|
1712
|
+
}
|
|
1713
|
+
function foldWorkflowAgentTime(activeSegments, spans) {
|
|
1714
|
+
if (spans.length === 0)
|
|
1715
|
+
return {};
|
|
1716
|
+
const all = [...activeSegments ?? [], ...spans].filter((s) => s.endMs > s.startMs).sort((a, b) => a.startMs - b.startMs);
|
|
1717
|
+
if (all.length === 0)
|
|
1718
|
+
return {};
|
|
1719
|
+
const merged = [{ ...all[0] }];
|
|
1720
|
+
for (let i = 1; i < all.length; i++) {
|
|
1721
|
+
const cur = all[i];
|
|
1722
|
+
const last = merged[merged.length - 1];
|
|
1723
|
+
if (cur.startMs <= last.endMs)
|
|
1724
|
+
last.endMs = Math.max(last.endMs, cur.endMs);
|
|
1725
|
+
else
|
|
1726
|
+
merged.push({ ...cur });
|
|
1727
|
+
}
|
|
1728
|
+
const airTimeMs = merged.reduce((n, s) => n + (s.endMs - s.startMs), 0);
|
|
1729
|
+
return { activeSegments: merged, airTimeMs };
|
|
1730
|
+
}
|
|
1646
1731
|
async function getCachedMeta(f) {
|
|
1647
1732
|
const cached = metaCache.get(f.fullPath);
|
|
1648
1733
|
if (cached && cached.mtimeMs === f.mtimeMs && cached.sizeBytes === f.sizeBytes) {
|
|
@@ -1654,12 +1739,15 @@ async function getCachedMeta(f) {
|
|
|
1654
1739
|
const sessionId = sessionIdFromFileName(f.fileName);
|
|
1655
1740
|
const projectDirPath = path.dirname(f.fullPath);
|
|
1656
1741
|
meta.totalUsage = await computeSessionUsageWithSubagents(rawLines, projectDirPath, sessionId);
|
|
1742
|
+
const wf = await scanWorkflowAggregate(projectDirPath, sessionId);
|
|
1657
1743
|
const full = {
|
|
1658
1744
|
...meta,
|
|
1659
1745
|
id: sessionId,
|
|
1660
1746
|
filePath: f.fullPath,
|
|
1661
1747
|
projectDir: f.projectDir,
|
|
1662
|
-
projectName: meta.cwd ?? decodeProjectName(f.projectDir)
|
|
1748
|
+
projectName: meta.cwd ?? decodeProjectName(f.projectDir),
|
|
1749
|
+
...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
|
|
1750
|
+
...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
|
|
1663
1751
|
};
|
|
1664
1752
|
metaCache.set(f.fullPath, { meta: full, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
|
|
1665
1753
|
return full;
|
|
@@ -1675,13 +1763,17 @@ async function getCachedDetail(f) {
|
|
|
1675
1763
|
try {
|
|
1676
1764
|
const rawLines = await readJsonlFile(f.fullPath);
|
|
1677
1765
|
const { meta, events } = parseTranscript(rawLines);
|
|
1766
|
+
const sessionId = sessionIdFromFileName(f.fileName);
|
|
1767
|
+
const wf = await scanWorkflowAggregate(path.dirname(f.fullPath), sessionId);
|
|
1678
1768
|
const detail = {
|
|
1679
1769
|
...meta,
|
|
1680
|
-
id:
|
|
1770
|
+
id: sessionId,
|
|
1681
1771
|
filePath: f.fullPath,
|
|
1682
1772
|
projectDir: f.projectDir,
|
|
1683
1773
|
projectName: meta.cwd ?? decodeProjectName(f.projectDir),
|
|
1684
|
-
events
|
|
1774
|
+
events,
|
|
1775
|
+
...wf.workflowCount > 0 ? { workflowCount: wf.workflowCount, spawnedAgentCount: wf.spawnedAgentCount } : {},
|
|
1776
|
+
...foldWorkflowAgentTime(meta.activeSegments, wf.spans)
|
|
1685
1777
|
};
|
|
1686
1778
|
detailCache.set(f.fullPath, { detail, mtimeMs: f.mtimeMs, sizeBytes: f.sizeBytes });
|
|
1687
1779
|
const metaOnly = { ...detail };
|
|
@@ -1713,8 +1805,18 @@ async function getSession(id, opts = {}) {
|
|
|
1713
1805
|
return detail;
|
|
1714
1806
|
const sessionStartMs = detail.firstTimestamp ? Date.parse(detail.firstTimestamp) : void 0;
|
|
1715
1807
|
const subagentsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "subagents");
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1808
|
+
const workflowsDir = path.join(path.dirname(hit.fullPath), sessionIdFromFileName(hit.fileName), "workflows");
|
|
1809
|
+
const [subagents, workflows] = await Promise.all([
|
|
1810
|
+
loadSubagents(subagentsDir, sessionStartMs, detail.events),
|
|
1811
|
+
loadWorkflows(workflowsDir, sessionStartMs, detail.events)
|
|
1812
|
+
]);
|
|
1813
|
+
const spawnedAgentCount = workflows.reduce((n, w) => n + w.agentCount, 0);
|
|
1814
|
+
return {
|
|
1815
|
+
...detail,
|
|
1816
|
+
subagents,
|
|
1817
|
+
workflows,
|
|
1818
|
+
...workflows.length > 0 ? { workflowCount: workflows.length, spawnedAgentCount } : {}
|
|
1819
|
+
};
|
|
1718
1820
|
}
|
|
1719
1821
|
function summarizeSubagentLines(lines) {
|
|
1720
1822
|
let startMs;
|
|
@@ -1904,6 +2006,248 @@ async function loadSubagents(dir, sessionStartMs, parentEvents) {
|
|
|
1904
2006
|
}));
|
|
1905
2007
|
return runs.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
|
|
1906
2008
|
}
|
|
2009
|
+
async function loadWorkflows(dir, sessionStartMs, parentEvents) {
|
|
2010
|
+
let entries;
|
|
2011
|
+
try {
|
|
2012
|
+
entries = await fs.readdir(dir);
|
|
2013
|
+
} catch {
|
|
2014
|
+
return [];
|
|
2015
|
+
}
|
|
2016
|
+
const jsonFiles = entries.filter((f) => f.startsWith("wf_") && f.endsWith(".json"));
|
|
2017
|
+
if (jsonFiles.length === 0)
|
|
2018
|
+
return [];
|
|
2019
|
+
const dispatches = [];
|
|
2020
|
+
for (const e of parentEvents) {
|
|
2021
|
+
if (e.role !== "tool-call" || e.toolName !== "Workflow")
|
|
2022
|
+
continue;
|
|
2023
|
+
const tsMs = e.timestamp ? Date.parse(e.timestamp) : NaN;
|
|
2024
|
+
if (Number.isNaN(tsMs))
|
|
2025
|
+
continue;
|
|
2026
|
+
for (const b of e.blocks) {
|
|
2027
|
+
if (b?.type !== "tool_use" || b.name !== "Workflow")
|
|
2028
|
+
continue;
|
|
2029
|
+
dispatches.push({ toolUseId: b.id, parentUuid: e.uuid ?? "", tsMs });
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
dispatches.sort((a, b) => a.tsMs - b.tsMs);
|
|
2033
|
+
const matchDispatch = (startMs) => {
|
|
2034
|
+
if (startMs === void 0 || dispatches.length === 0)
|
|
2035
|
+
return void 0;
|
|
2036
|
+
const TOLERANCE_MS = 6e4;
|
|
2037
|
+
let before;
|
|
2038
|
+
let beforeDelta = Infinity;
|
|
2039
|
+
let nearest;
|
|
2040
|
+
let nearestDelta = Infinity;
|
|
2041
|
+
for (const d of dispatches) {
|
|
2042
|
+
const delta = Math.abs(startMs - d.tsMs);
|
|
2043
|
+
if (delta > TOLERANCE_MS)
|
|
2044
|
+
continue;
|
|
2045
|
+
if (delta < nearestDelta) {
|
|
2046
|
+
nearest = d;
|
|
2047
|
+
nearestDelta = delta;
|
|
2048
|
+
}
|
|
2049
|
+
if (d.tsMs <= startMs && delta < beforeDelta) {
|
|
2050
|
+
before = d;
|
|
2051
|
+
beforeDelta = delta;
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
return before ?? nearest;
|
|
2055
|
+
};
|
|
2056
|
+
const num2 = (v) => typeof v === "number" ? v : void 0;
|
|
2057
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
2058
|
+
const runs = await Promise.all(jsonFiles.map(async (f) => {
|
|
2059
|
+
let j;
|
|
2060
|
+
try {
|
|
2061
|
+
j = JSON.parse(await fs.readFile(path.join(dir, f), "utf8"));
|
|
2062
|
+
} catch {
|
|
2063
|
+
return null;
|
|
2064
|
+
}
|
|
2065
|
+
const runId = str(j.runId) ?? f.replace(/\.json$/, "");
|
|
2066
|
+
const startMs = num2(j.startTime);
|
|
2067
|
+
const durationMs = num2(j.durationMs);
|
|
2068
|
+
const endMs = startMs !== void 0 && durationMs !== void 0 ? startMs + durationMs : void 0;
|
|
2069
|
+
const startTOffsetMs = sessionStartMs !== void 0 && startMs !== void 0 ? Math.max(0, startMs - sessionStartMs) : void 0;
|
|
2070
|
+
const endTOffsetMs = sessionStartMs !== void 0 && endMs !== void 0 ? Math.max(0, endMs - sessionStartMs) : void 0;
|
|
2071
|
+
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) })) : [];
|
|
2072
|
+
const logs = Array.isArray(j.logs) ? j.logs.filter((l) => typeof l === "string") : [];
|
|
2073
|
+
const cap = (v, n) => {
|
|
2074
|
+
const s = str(v);
|
|
2075
|
+
return s === void 0 ? void 0 : s.length > n ? s.slice(0, n) + "\u2026" : s;
|
|
2076
|
+
};
|
|
2077
|
+
const progress = Array.isArray(j.workflowProgress) ? j.workflowProgress : [];
|
|
2078
|
+
const agents = progress.filter((e) => !!e && typeof e === "object" && e.type === "workflow_agent").map((e) => ({
|
|
2079
|
+
index: num2(e.index) ?? 0,
|
|
2080
|
+
label: str(e.label) ?? "(agent)",
|
|
2081
|
+
phaseIndex: num2(e.phaseIndex),
|
|
2082
|
+
phaseTitle: str(e.phaseTitle),
|
|
2083
|
+
agentId: str(e.agentId),
|
|
2084
|
+
model: str(e.model),
|
|
2085
|
+
state: str(e.state),
|
|
2086
|
+
startedAt: num2(e.startedAt),
|
|
2087
|
+
durationMs: num2(e.durationMs),
|
|
2088
|
+
tokens: num2(e.tokens),
|
|
2089
|
+
toolCalls: num2(e.toolCalls),
|
|
2090
|
+
lastToolSummary: cap(e.lastToolSummary, 200),
|
|
2091
|
+
promptPreview: cap(e.promptPreview, 600),
|
|
2092
|
+
resultPreview: cap(e.resultPreview, 600)
|
|
2093
|
+
})).sort((a, b) => a.index - b.index);
|
|
2094
|
+
const parent = matchDispatch(startMs);
|
|
2095
|
+
return {
|
|
2096
|
+
runId,
|
|
2097
|
+
name: str(j.workflowName) ?? runId,
|
|
2098
|
+
description: str(j.summary),
|
|
2099
|
+
status: str(j.status) ?? "unknown",
|
|
2100
|
+
agentCount: num2(j.agentCount) ?? 0,
|
|
2101
|
+
toolCallCount: num2(j.totalToolCalls) ?? 0,
|
|
2102
|
+
totalTokens: num2(j.totalTokens) ?? 0,
|
|
2103
|
+
durationMs,
|
|
2104
|
+
startMs,
|
|
2105
|
+
endMs,
|
|
2106
|
+
startTOffsetMs,
|
|
2107
|
+
endTOffsetMs,
|
|
2108
|
+
model: str(j.defaultModel),
|
|
2109
|
+
phases,
|
|
2110
|
+
logs,
|
|
2111
|
+
agents,
|
|
2112
|
+
parentToolUseId: parent?.toolUseId,
|
|
2113
|
+
parentUuid: parent?.parentUuid
|
|
2114
|
+
};
|
|
2115
|
+
}));
|
|
2116
|
+
return runs.filter((r) => r !== null).sort((a, b) => (a.startMs ?? 0) - (b.startMs ?? 0));
|
|
2117
|
+
}
|
|
2118
|
+
function salientToolInput(input) {
|
|
2119
|
+
if (!input || typeof input !== "object")
|
|
2120
|
+
return "";
|
|
2121
|
+
const o = input;
|
|
2122
|
+
const pick = (k) => typeof o[k] === "string" ? o[k] : void 0;
|
|
2123
|
+
return pick("command") ?? pick("file_path") ?? pick("path") ?? pick("pattern") ?? pick("url") ?? pick("description") ?? pick("query") ?? pick("prompt") ?? pick("old_string") ?? JSON.stringify(o);
|
|
2124
|
+
}
|
|
2125
|
+
async function loadWorkflowAgentDetail(sessionId, runId, agentId, opts = {}) {
|
|
2126
|
+
const { root = DEFAULT_ROOT } = opts;
|
|
2127
|
+
if (!/^[\w.-]+$/.test(runId) || !/^[\w.-]+$/.test(agentId))
|
|
2128
|
+
return null;
|
|
2129
|
+
const files = await walkJsonlFiles(root);
|
|
2130
|
+
const hit = files.find((f) => sessionIdFromFileName(f.fileName) === sessionId);
|
|
2131
|
+
if (!hit)
|
|
2132
|
+
return null;
|
|
2133
|
+
const file = path.join(path.dirname(hit.fullPath), sessionId, "subagents", "workflows", runId, `agent-${agentId}.jsonl`);
|
|
2134
|
+
let lines;
|
|
2135
|
+
try {
|
|
2136
|
+
lines = await readJsonlFile(file);
|
|
2137
|
+
} catch {
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
const errored = /* @__PURE__ */ new Set();
|
|
2141
|
+
for (const raw of lines) {
|
|
2142
|
+
if (!raw || typeof raw !== "object")
|
|
2143
|
+
continue;
|
|
2144
|
+
const content = raw.message?.content;
|
|
2145
|
+
if (!Array.isArray(content))
|
|
2146
|
+
continue;
|
|
2147
|
+
for (const b of content) {
|
|
2148
|
+
if (b && typeof b === "object" && b.type === "tool_result" && b.is_error === true && typeof b.tool_use_id === "string") {
|
|
2149
|
+
errored.add(b.tool_use_id);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
const steps = [];
|
|
2154
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
2155
|
+
const totalUsage = { ...BLANK_USAGE3 };
|
|
2156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2157
|
+
let prompt;
|
|
2158
|
+
let finalText;
|
|
2159
|
+
let model;
|
|
2160
|
+
let assistantMessageCount = 0;
|
|
2161
|
+
let eventCount = 0;
|
|
2162
|
+
let startMs;
|
|
2163
|
+
let endMs;
|
|
2164
|
+
for (const raw of lines) {
|
|
2165
|
+
if (!raw || typeof raw !== "object")
|
|
2166
|
+
continue;
|
|
2167
|
+
const r = raw;
|
|
2168
|
+
eventCount++;
|
|
2169
|
+
const ts = typeof r.timestamp === "string" ? Date.parse(r.timestamp) : NaN;
|
|
2170
|
+
if (!Number.isNaN(ts)) {
|
|
2171
|
+
if (startMs === void 0 || ts < startMs)
|
|
2172
|
+
startMs = ts;
|
|
2173
|
+
if (endMs === void 0 || ts > endMs)
|
|
2174
|
+
endMs = ts;
|
|
2175
|
+
}
|
|
2176
|
+
if (prompt === void 0 && r.type === "user" && (r.parentUuid === null || r.parentUuid === void 0)) {
|
|
2177
|
+
const c = r.message?.content;
|
|
2178
|
+
if (typeof c === "string")
|
|
2179
|
+
prompt = c;
|
|
2180
|
+
else if (Array.isArray(c)) {
|
|
2181
|
+
const t = c.find((b) => b && typeof b === "object" && b.type === "text");
|
|
2182
|
+
if (t?.text)
|
|
2183
|
+
prompt = t.text;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
if (r.type !== "assistant")
|
|
2187
|
+
continue;
|
|
2188
|
+
const m = r.message;
|
|
2189
|
+
if (!m)
|
|
2190
|
+
continue;
|
|
2191
|
+
if (!model && typeof m.model === "string")
|
|
2192
|
+
model = m.model;
|
|
2193
|
+
const mid = typeof m.id === "string" ? m.id : void 0;
|
|
2194
|
+
const rid = typeof r.requestId === "string" ? r.requestId : void 0;
|
|
2195
|
+
const key = mid != null && rid != null ? `${mid}:${rid}` : void 0;
|
|
2196
|
+
const fresh = key ? !seen.has(key) : true;
|
|
2197
|
+
if (key && fresh)
|
|
2198
|
+
seen.add(key);
|
|
2199
|
+
if (fresh) {
|
|
2200
|
+
assistantMessageCount++;
|
|
2201
|
+
const u = m.usage;
|
|
2202
|
+
if (u) {
|
|
2203
|
+
const n = (v) => typeof v === "number" ? v : 0;
|
|
2204
|
+
totalUsage.input += n(u.input_tokens);
|
|
2205
|
+
totalUsage.output += n(u.output_tokens);
|
|
2206
|
+
totalUsage.cacheRead += n(u.cache_read_input_tokens);
|
|
2207
|
+
totalUsage.cacheWrite += n(u.cache_creation_input_tokens);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
const content = m.content;
|
|
2211
|
+
if (!Array.isArray(content))
|
|
2212
|
+
continue;
|
|
2213
|
+
for (const b of content) {
|
|
2214
|
+
if (!b || typeof b !== "object")
|
|
2215
|
+
continue;
|
|
2216
|
+
if (b.type === "text" && typeof b.text === "string") {
|
|
2217
|
+
finalText = b.text;
|
|
2218
|
+
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
2219
|
+
toolCounts.set(b.name, (toolCounts.get(b.name) ?? 0) + 1);
|
|
2220
|
+
if (steps.length < 2e3) {
|
|
2221
|
+
const salient = salientToolInput(b.input);
|
|
2222
|
+
const preview = salient.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
2223
|
+
const full = salient.length > 4e3 ? salient.slice(0, 4e3) + "\u2026" : salient;
|
|
2224
|
+
steps.push({
|
|
2225
|
+
index: steps.length + 1,
|
|
2226
|
+
tool: b.name,
|
|
2227
|
+
preview,
|
|
2228
|
+
// Only carry `full` when it adds something over the one-line preview.
|
|
2229
|
+
full: full.length > preview.length || full.includes("\n") ? full : void 0,
|
|
2230
|
+
isError: typeof b.id === "string" && errored.has(b.id)
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
const toolCalls = Array.from(toolCounts.entries()).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
|
|
2237
|
+
return {
|
|
2238
|
+
agentId,
|
|
2239
|
+
prompt,
|
|
2240
|
+
finalText,
|
|
2241
|
+
steps,
|
|
2242
|
+
toolCalls,
|
|
2243
|
+
toolCallCount: steps.length,
|
|
2244
|
+
assistantMessageCount,
|
|
2245
|
+
eventCount,
|
|
2246
|
+
totalUsage,
|
|
2247
|
+
model,
|
|
2248
|
+
durationMs: startMs !== void 0 && endMs !== void 0 ? endMs - startMs : void 0
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
1907
2251
|
async function listProjects(root = DEFAULT_ROOT) {
|
|
1908
2252
|
const files = await walkJsonlFiles(root);
|
|
1909
2253
|
const byRawDir = /* @__PURE__ */ new Map();
|
|
@@ -1925,10 +2269,10 @@ async function listProjects(root = DEFAULT_ROOT) {
|
|
|
1925
2269
|
const canonicalMap = /* @__PURE__ */ new Map();
|
|
1926
2270
|
for (const [rawDir, { count, lastActiveMs }] of byRawDir) {
|
|
1927
2271
|
const cwdOrDecoded = cwdForProject(rawDir) ?? decodeProjectName(rawDir);
|
|
1928
|
-
const
|
|
2272
|
+
const repo = projectRepoName(cwdOrDecoded);
|
|
1929
2273
|
const wt = worktreeName(cwdOrDecoded);
|
|
1930
|
-
const agg = canonicalMap.get(
|
|
1931
|
-
canonicalName:
|
|
2274
|
+
const agg = canonicalMap.get(repo) ?? {
|
|
2275
|
+
canonicalName: repo,
|
|
1932
2276
|
count: 0,
|
|
1933
2277
|
lastActiveMs: 0,
|
|
1934
2278
|
worktreeBranches: /* @__PURE__ */ new Set()
|
|
@@ -1938,7 +2282,7 @@ async function listProjects(root = DEFAULT_ROOT) {
|
|
|
1938
2282
|
agg.lastActiveMs = lastActiveMs;
|
|
1939
2283
|
if (wt)
|
|
1940
2284
|
agg.worktreeBranches.add(wt);
|
|
1941
|
-
canonicalMap.set(
|
|
2285
|
+
canonicalMap.set(repo, agg);
|
|
1942
2286
|
}
|
|
1943
2287
|
return Array.from(canonicalMap.values()).map((a) => ({
|
|
1944
2288
|
projectDir: a.canonicalName,
|
|
@@ -2838,76 +3182,705 @@ async function parseSession(file) {
|
|
|
2838
3182
|
prevMs = ms;
|
|
2839
3183
|
}
|
|
2840
3184
|
}
|
|
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;
|
|
3185
|
+
const activeSegments = computeActiveSegments3(tsMs);
|
|
3186
|
+
const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
|
|
3187
|
+
const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
|
|
3188
|
+
const sessionId = metaRec.sessionId ?? file.filenameId;
|
|
3189
|
+
const projectName = cwd ? canonicalProjectName(cwd) : file.slug;
|
|
3190
|
+
const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.slug;
|
|
3191
|
+
const meta = {
|
|
3192
|
+
agent: "gemini",
|
|
3193
|
+
id: sessionId,
|
|
3194
|
+
filePath: file.filePath,
|
|
3195
|
+
projectName,
|
|
3196
|
+
projectDir,
|
|
3197
|
+
sessionId,
|
|
3198
|
+
firstTimestamp,
|
|
3199
|
+
lastTimestamp,
|
|
3200
|
+
durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
|
|
3201
|
+
eventCount: events.length,
|
|
3202
|
+
model,
|
|
3203
|
+
cwd,
|
|
3204
|
+
totalUsage,
|
|
3205
|
+
status: "idle",
|
|
3206
|
+
firstUserPreview,
|
|
3207
|
+
lastUserPreview,
|
|
3208
|
+
lastAgentPreview,
|
|
3209
|
+
toolCallCount,
|
|
3210
|
+
turnCount,
|
|
3211
|
+
airTimeMs,
|
|
3212
|
+
activeSegments
|
|
3213
|
+
};
|
|
3214
|
+
return { meta, events };
|
|
3215
|
+
}
|
|
3216
|
+
function computeActiveSegments3(tsMs) {
|
|
3217
|
+
if (tsMs.length === 0)
|
|
3218
|
+
return [];
|
|
3219
|
+
const sorted = [...tsMs].sort((a, b) => a - b);
|
|
3220
|
+
const out = [];
|
|
3221
|
+
let segStart = sorted[0];
|
|
3222
|
+
let segEnd = sorted[0];
|
|
3223
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
3224
|
+
if (sorted[i] - segEnd > IDLE_GAP_MS2) {
|
|
3225
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3226
|
+
segStart = sorted[i];
|
|
3227
|
+
}
|
|
3228
|
+
segEnd = sorted[i];
|
|
3229
|
+
}
|
|
3230
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3231
|
+
return out;
|
|
3232
|
+
}
|
|
3233
|
+
function clearGeminiCaches() {
|
|
3234
|
+
metaCache3.clear();
|
|
3235
|
+
detailCache3.clear();
|
|
3236
|
+
projectsCache = null;
|
|
3237
|
+
}
|
|
3238
|
+
async function listGeminiSessions(opts = {}) {
|
|
3239
|
+
const root = opts.root ?? DEFAULT_GEMINI_ROOT;
|
|
3240
|
+
const files = await listSessionFiles(root);
|
|
3241
|
+
const out = [];
|
|
3242
|
+
for (const file of files) {
|
|
3243
|
+
const cached = metaCache3.get(file.filePath);
|
|
3244
|
+
if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes) {
|
|
3245
|
+
out.push(cached.meta);
|
|
3246
|
+
continue;
|
|
3247
|
+
}
|
|
3248
|
+
try {
|
|
3249
|
+
const { meta } = await parseSession(file);
|
|
3250
|
+
metaCache3.set(file.filePath, {
|
|
3251
|
+
meta,
|
|
3252
|
+
mtimeMs: file.mtimeMs,
|
|
3253
|
+
sizeBytes: file.sizeBytes
|
|
3254
|
+
});
|
|
3255
|
+
out.push(meta);
|
|
3256
|
+
} catch {
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
|
|
3260
|
+
if (opts.limit !== void 0)
|
|
3261
|
+
return out.slice(0, opts.limit);
|
|
3262
|
+
return out;
|
|
3263
|
+
}
|
|
3264
|
+
async function getGeminiSession(id, opts = {}) {
|
|
3265
|
+
const root = opts.root ?? DEFAULT_GEMINI_ROOT;
|
|
3266
|
+
const files = await listSessionFiles(root);
|
|
3267
|
+
let chosen;
|
|
3268
|
+
for (const file of files) {
|
|
3269
|
+
if (file.filenameId === id || id.startsWith(file.filenameId)) {
|
|
3270
|
+
chosen = file;
|
|
3271
|
+
break;
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
if (!chosen) {
|
|
3275
|
+
for (const file of files) {
|
|
3276
|
+
const { meta: meta2 } = await parseSession(file).catch(() => ({ meta: { id: "" } }));
|
|
3277
|
+
if (meta2.id === id) {
|
|
3278
|
+
chosen = file;
|
|
3279
|
+
break;
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
if (!chosen)
|
|
3284
|
+
return null;
|
|
3285
|
+
const cached = detailCache3.get(chosen.filePath);
|
|
3286
|
+
if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes) {
|
|
3287
|
+
return cached.detail;
|
|
3288
|
+
}
|
|
3289
|
+
const { meta, events } = await parseSession(chosen);
|
|
3290
|
+
const detail = { ...meta, events };
|
|
3291
|
+
detailCache3.set(chosen.filePath, {
|
|
3292
|
+
detail,
|
|
3293
|
+
mtimeMs: chosen.mtimeMs,
|
|
3294
|
+
sizeBytes: chosen.sizeBytes
|
|
3295
|
+
});
|
|
3296
|
+
return detail;
|
|
3297
|
+
}
|
|
3298
|
+
function geminiSessionLocalDay(meta) {
|
|
3299
|
+
if (!meta.firstTimestamp)
|
|
3300
|
+
return void 0;
|
|
3301
|
+
const ms = Date.parse(meta.firstTimestamp);
|
|
3302
|
+
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
3303
|
+
}
|
|
3304
|
+
var DEFAULT_GEMINI_ROOT, GEMINI_PROJECTS_FILE, SESSION_FILE_RE, IDLE_GAP_MS2, projectsCache, metaCache3, detailCache3;
|
|
3305
|
+
var init_gemini = __esm({
|
|
3306
|
+
"../parser/dist/gemini.js"() {
|
|
3307
|
+
"use strict";
|
|
3308
|
+
init_analytics();
|
|
3309
|
+
init_user_input();
|
|
3310
|
+
DEFAULT_GEMINI_ROOT = path3.join(os3.homedir(), ".gemini", "tmp");
|
|
3311
|
+
GEMINI_PROJECTS_FILE = path3.join(os3.homedir(), ".gemini", "projects.json");
|
|
3312
|
+
SESSION_FILE_RE = /^session-.+\.(jsonl|json)$/;
|
|
3313
|
+
IDLE_GAP_MS2 = 3 * 60 * 1e3;
|
|
3314
|
+
projectsCache = null;
|
|
3315
|
+
metaCache3 = /* @__PURE__ */ new Map();
|
|
3316
|
+
detailCache3 = /* @__PURE__ */ new Map();
|
|
3317
|
+
}
|
|
3318
|
+
});
|
|
3319
|
+
|
|
3320
|
+
// ../parser/dist/antigravity.js
|
|
3321
|
+
import { promises as fs4 } from "node:fs";
|
|
3322
|
+
import os4 from "node:os";
|
|
3323
|
+
import path4 from "node:path";
|
|
3324
|
+
async function safeReaddir3(p) {
|
|
3325
|
+
return fs4.readdir(p).catch(() => []);
|
|
3326
|
+
}
|
|
3327
|
+
async function loadSlugToCwd2(root) {
|
|
3328
|
+
const historyFile = path4.join(root, "history.jsonl");
|
|
3329
|
+
const stat = await fs4.stat(historyFile).catch(() => null);
|
|
3330
|
+
if (!stat)
|
|
3331
|
+
return /* @__PURE__ */ new Map();
|
|
3332
|
+
if (historyCache && historyCache.mtimeMs === stat.mtimeMs) {
|
|
3333
|
+
return historyCache.slugToCwd;
|
|
3334
|
+
}
|
|
3335
|
+
const raw = await fs4.readFile(historyFile, "utf8").catch(() => "");
|
|
3336
|
+
const slugToCwd = /* @__PURE__ */ new Map();
|
|
3337
|
+
for (const line of raw.split("\n")) {
|
|
3338
|
+
const trimmed = line.trim();
|
|
3339
|
+
if (!trimmed)
|
|
3340
|
+
continue;
|
|
3341
|
+
try {
|
|
3342
|
+
const parsed = JSON.parse(trimmed);
|
|
3343
|
+
if (parsed.conversationId && parsed.workspace) {
|
|
3344
|
+
slugToCwd.set(parsed.conversationId, parsed.workspace);
|
|
3345
|
+
}
|
|
3346
|
+
} catch {
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
historyCache = { mtimeMs: stat.mtimeMs, slugToCwd };
|
|
3350
|
+
return slugToCwd;
|
|
3351
|
+
}
|
|
3352
|
+
async function listSessionFiles2(root) {
|
|
3353
|
+
const slugToCwd = await loadSlugToCwd2(root);
|
|
3354
|
+
const out = [];
|
|
3355
|
+
const brainDir = path4.join(root, "brain");
|
|
3356
|
+
const entries = await safeReaddir3(brainDir);
|
|
3357
|
+
for (const entry of entries) {
|
|
3358
|
+
const transcriptPath = path4.join(brainDir, entry, ".system_generated", "logs", "transcript.jsonl");
|
|
3359
|
+
const stat = await fs4.stat(transcriptPath).catch(() => null);
|
|
3360
|
+
if (stat && stat.isFile()) {
|
|
3361
|
+
out.push({
|
|
3362
|
+
filePath: transcriptPath,
|
|
3363
|
+
conversationId: entry,
|
|
3364
|
+
cwd: slugToCwd.get(entry),
|
|
3365
|
+
mtimeMs: stat.mtimeMs,
|
|
3366
|
+
sizeBytes: stat.size
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
return out;
|
|
3371
|
+
}
|
|
3372
|
+
function emptyUsage3() {
|
|
3373
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
3374
|
+
}
|
|
3375
|
+
function previewOf3(text) {
|
|
3376
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
3377
|
+
}
|
|
3378
|
+
function truncate4(s, n) {
|
|
3379
|
+
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
3380
|
+
}
|
|
3381
|
+
async function parseSession2(file) {
|
|
3382
|
+
const raw = await fs4.readFile(file.filePath, "utf8");
|
|
3383
|
+
const events = [];
|
|
3384
|
+
const totalUsage = emptyUsage3();
|
|
3385
|
+
let firstTimestamp;
|
|
3386
|
+
let lastTimestamp;
|
|
3387
|
+
let model;
|
|
3388
|
+
let toolCallCount = 0;
|
|
3389
|
+
let turnCount = 0;
|
|
3390
|
+
let firstUserPreview;
|
|
3391
|
+
let lastUserPreview;
|
|
3392
|
+
let lastAgentPreview;
|
|
3393
|
+
const tsMs = [];
|
|
3394
|
+
let idx = 0;
|
|
3395
|
+
function pushEvent(e) {
|
|
3396
|
+
events.push(e);
|
|
3397
|
+
if (e.timestamp && e.role !== "meta") {
|
|
3398
|
+
if (!firstTimestamp)
|
|
3399
|
+
firstTimestamp = e.timestamp;
|
|
3400
|
+
lastTimestamp = e.timestamp;
|
|
3401
|
+
const ms = Date.parse(e.timestamp);
|
|
3402
|
+
if (Number.isFinite(ms))
|
|
3403
|
+
tsMs.push(ms);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
const pendingToolCalls = [];
|
|
3407
|
+
const parsedObjects = [];
|
|
3408
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
3409
|
+
for (const line of raw.split("\n")) {
|
|
3410
|
+
const trimmed = line.trim();
|
|
3411
|
+
if (!trimmed)
|
|
3412
|
+
continue;
|
|
3413
|
+
try {
|
|
3414
|
+
const obj = JSON.parse(trimmed);
|
|
3415
|
+
const stepIdx = obj.step_index;
|
|
3416
|
+
if (typeof stepIdx === "number") {
|
|
3417
|
+
if (indexMap.has(stepIdx)) {
|
|
3418
|
+
parsedObjects[indexMap.get(stepIdx)] = obj;
|
|
3419
|
+
} else {
|
|
3420
|
+
indexMap.set(stepIdx, parsedObjects.length);
|
|
3421
|
+
parsedObjects.push(obj);
|
|
3422
|
+
}
|
|
3423
|
+
} else {
|
|
3424
|
+
parsedObjects.push(obj);
|
|
3425
|
+
}
|
|
3426
|
+
} catch {
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
for (const eventObj of parsedObjects) {
|
|
3430
|
+
const ts = eventObj.created_at || eventObj.timestamp;
|
|
3431
|
+
if (eventObj.type === "USER_INPUT") {
|
|
3432
|
+
if (typeof eventObj.content === "string") {
|
|
3433
|
+
const matchNoNeed = eventObj.content.match(/Model Selection` from .*? to (.*?)\.\s*No need to/);
|
|
3434
|
+
if (matchNoNeed) {
|
|
3435
|
+
let rawModel = matchNoNeed[1].trim();
|
|
3436
|
+
rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
|
|
3437
|
+
model = rawModel;
|
|
3438
|
+
} else {
|
|
3439
|
+
const matchDot = eventObj.content.match(/Model Selection` from .*? to ([^\n]+)/);
|
|
3440
|
+
if (matchDot) {
|
|
3441
|
+
let rawModel = matchDot[1].trim();
|
|
3442
|
+
if (rawModel.endsWith(".")) {
|
|
3443
|
+
rawModel = rawModel.slice(0, -1).trim();
|
|
3444
|
+
}
|
|
3445
|
+
rawModel = rawModel.replace(/\s*\(.*?\)\s*$/, "").trim();
|
|
3446
|
+
model = rawModel;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
let text2 = eventObj.content || "";
|
|
3451
|
+
const requestMatch = text2.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
3452
|
+
if (requestMatch) {
|
|
3453
|
+
text2 = requestMatch[1].trim();
|
|
3454
|
+
}
|
|
3455
|
+
const preview = previewOf3(text2);
|
|
3456
|
+
const isHidden = isFrameworkInjectedUserInput(text2);
|
|
3457
|
+
if (text2 && !isHidden) {
|
|
3458
|
+
if (!firstUserPreview)
|
|
3459
|
+
firstUserPreview = preview;
|
|
3460
|
+
lastUserPreview = preview;
|
|
3461
|
+
turnCount += 1;
|
|
3462
|
+
}
|
|
3463
|
+
pushEvent({
|
|
3464
|
+
index: idx++,
|
|
3465
|
+
timestamp: ts,
|
|
3466
|
+
role: "user",
|
|
3467
|
+
rawType: "antigravity/user",
|
|
3468
|
+
preview,
|
|
3469
|
+
blocks: text2 ? [{ type: "text", text: text2 }] : [],
|
|
3470
|
+
messageId: eventObj.step_index?.toString(),
|
|
3471
|
+
raw: eventObj
|
|
3472
|
+
});
|
|
3473
|
+
continue;
|
|
3474
|
+
}
|
|
3475
|
+
if (eventObj.type === "PLANNER_RESPONSE") {
|
|
3476
|
+
const thinking = eventObj.thinking;
|
|
3477
|
+
const content = eventObj.content;
|
|
3478
|
+
if (thinking) {
|
|
3479
|
+
pushEvent({
|
|
3480
|
+
index: idx++,
|
|
3481
|
+
timestamp: ts,
|
|
3482
|
+
role: "agent-thinking",
|
|
3483
|
+
rawType: "antigravity/thought",
|
|
3484
|
+
preview: previewOf3(thinking),
|
|
3485
|
+
blocks: [{ type: "thinking", thinking }],
|
|
3486
|
+
model,
|
|
3487
|
+
raw: eventObj
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
if (content) {
|
|
3491
|
+
const preview = previewOf3(content);
|
|
3492
|
+
lastAgentPreview = preview;
|
|
3493
|
+
pushEvent({
|
|
3494
|
+
index: idx++,
|
|
3495
|
+
timestamp: ts,
|
|
3496
|
+
role: "agent",
|
|
3497
|
+
rawType: "antigravity/agent",
|
|
3498
|
+
preview,
|
|
3499
|
+
blocks: [{ type: "text", text: content }],
|
|
3500
|
+
messageId: eventObj.step_index?.toString(),
|
|
3501
|
+
model,
|
|
3502
|
+
raw: eventObj
|
|
3503
|
+
});
|
|
3504
|
+
}
|
|
3505
|
+
const toolCalls = eventObj.tool_calls || [];
|
|
3506
|
+
for (let cIdx = 0; cIdx < toolCalls.length; cIdx++) {
|
|
3507
|
+
const tc = toolCalls[cIdx];
|
|
3508
|
+
toolCallCount += 1;
|
|
3509
|
+
const toolUseId = `tool-${eventObj.step_index}-${cIdx}`;
|
|
3510
|
+
const argsStr = tc.args ? JSON.stringify(tc.args) : "";
|
|
3511
|
+
pendingToolCalls.push({ id: toolUseId, name: tc.name });
|
|
3512
|
+
pushEvent({
|
|
3513
|
+
index: idx++,
|
|
3514
|
+
timestamp: ts,
|
|
3515
|
+
role: "tool-call",
|
|
3516
|
+
rawType: "antigravity/tool_call",
|
|
3517
|
+
preview: `${tc.name}(${truncate4(argsStr, 80)})`,
|
|
3518
|
+
blocks: [{ type: "tool_use", id: toolUseId, name: tc.name, input: tc.args || {} }],
|
|
3519
|
+
toolName: tc.name,
|
|
3520
|
+
toolUseId,
|
|
3521
|
+
model,
|
|
3522
|
+
raw: tc
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
continue;
|
|
3526
|
+
}
|
|
3527
|
+
if (eventObj.source === "MODEL" && eventObj.type !== "PLANNER_RESPONSE" && eventObj.type !== "ERROR_MESSAGE" && pendingToolCalls.length > 0) {
|
|
3528
|
+
const matchedCall = pendingToolCalls.shift();
|
|
3529
|
+
const toolUseId = matchedCall ? matchedCall.id : `tool-${eventObj.step_index}-unknown`;
|
|
3530
|
+
const contentStr = typeof eventObj.content === "string" ? eventObj.content : JSON.stringify(eventObj.content || "");
|
|
3531
|
+
const isError = eventObj.status === "ERROR" || eventObj.status === "FAILED" || eventObj.status === "CANCELED" || !!eventObj.error;
|
|
3532
|
+
pushEvent({
|
|
3533
|
+
index: idx++,
|
|
3534
|
+
timestamp: ts,
|
|
3535
|
+
role: "tool-result",
|
|
3536
|
+
rawType: "antigravity/tool_result",
|
|
3537
|
+
preview: previewOf3(contentStr),
|
|
3538
|
+
blocks: [{
|
|
3539
|
+
type: "tool_result",
|
|
3540
|
+
tool_use_id: toolUseId,
|
|
3541
|
+
content: contentStr,
|
|
3542
|
+
is_error: isError
|
|
3543
|
+
}],
|
|
3544
|
+
toolUseId,
|
|
3545
|
+
toolResult: contentStr,
|
|
3546
|
+
raw: eventObj
|
|
3547
|
+
});
|
|
3548
|
+
continue;
|
|
3549
|
+
}
|
|
3550
|
+
const text = eventObj.content || eventObj.error || "";
|
|
3551
|
+
pushEvent({
|
|
3552
|
+
index: idx++,
|
|
3553
|
+
timestamp: ts,
|
|
3554
|
+
role: "meta",
|
|
3555
|
+
rawType: `antigravity/${eventObj.type?.toLowerCase() || "unknown"}`,
|
|
3556
|
+
preview: previewOf3(text),
|
|
3557
|
+
blocks: text ? [{ type: "text", text }] : [],
|
|
3558
|
+
raw: eventObj
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3561
|
+
const startMs = firstTimestamp ? Date.parse(firstTimestamp) : void 0;
|
|
3562
|
+
if (startMs !== void 0 && Number.isFinite(startMs)) {
|
|
3563
|
+
let prevMs;
|
|
3564
|
+
for (const ev of events) {
|
|
3565
|
+
if (!ev.timestamp)
|
|
3566
|
+
continue;
|
|
3567
|
+
const ms = Date.parse(ev.timestamp);
|
|
3568
|
+
if (!Number.isFinite(ms))
|
|
3569
|
+
continue;
|
|
3570
|
+
ev.tOffsetMs = Math.max(0, ms - startMs);
|
|
3571
|
+
if (prevMs !== void 0)
|
|
3572
|
+
ev.gapMs = Math.max(0, ms - prevMs);
|
|
3573
|
+
prevMs = ms;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
const activeSegments = computeActiveSegments4(tsMs);
|
|
3577
|
+
const airTimeMs = activeSegments.reduce((acc, s) => acc + (s.endMs - s.startMs), 0);
|
|
3578
|
+
const durationMs = firstTimestamp && lastTimestamp ? Date.parse(lastTimestamp) - Date.parse(firstTimestamp) : void 0;
|
|
3579
|
+
const sessionId = file.conversationId;
|
|
3580
|
+
const cwd = file.cwd;
|
|
3581
|
+
const projectName = cwd ? canonicalProjectName(cwd) : file.conversationId;
|
|
3582
|
+
const projectDir = cwd ? cwd.replace(/^\//, "-").replace(/\//g, "-") : file.conversationId;
|
|
3583
|
+
const meta = {
|
|
3584
|
+
agent: "antigravity",
|
|
3585
|
+
id: sessionId,
|
|
3586
|
+
filePath: file.filePath,
|
|
3587
|
+
projectName,
|
|
3588
|
+
projectDir,
|
|
3589
|
+
sessionId,
|
|
3590
|
+
firstTimestamp,
|
|
3591
|
+
lastTimestamp,
|
|
3592
|
+
durationMs: durationMs && Number.isFinite(durationMs) ? durationMs : void 0,
|
|
3593
|
+
eventCount: events.length,
|
|
3594
|
+
model,
|
|
3595
|
+
cwd,
|
|
3596
|
+
totalUsage,
|
|
3597
|
+
status: "idle",
|
|
3598
|
+
firstUserPreview,
|
|
3599
|
+
lastUserPreview,
|
|
3600
|
+
lastAgentPreview,
|
|
3601
|
+
toolCallCount,
|
|
3602
|
+
turnCount,
|
|
3603
|
+
airTimeMs,
|
|
3604
|
+
activeSegments
|
|
3605
|
+
};
|
|
3606
|
+
return { meta, events };
|
|
3607
|
+
}
|
|
3608
|
+
function computeActiveSegments4(tsMs) {
|
|
3609
|
+
if (tsMs.length === 0)
|
|
3610
|
+
return [];
|
|
3611
|
+
const sorted = [...tsMs].sort((a, b) => a - b);
|
|
3612
|
+
const out = [];
|
|
3613
|
+
let segStart = sorted[0];
|
|
3614
|
+
let segEnd = sorted[0];
|
|
3615
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
3616
|
+
if (sorted[i] - segEnd > IDLE_GAP_MS3) {
|
|
3617
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3618
|
+
segStart = sorted[i];
|
|
3619
|
+
}
|
|
3620
|
+
segEnd = sorted[i];
|
|
3621
|
+
}
|
|
3622
|
+
out.push({ startMs: segStart, endMs: segEnd });
|
|
3623
|
+
return out;
|
|
3624
|
+
}
|
|
3625
|
+
function clearAntigravityCaches() {
|
|
3626
|
+
metaCache4.clear();
|
|
3627
|
+
detailCache4.clear();
|
|
3628
|
+
historyCache = null;
|
|
3629
|
+
}
|
|
3630
|
+
async function listAntigravitySessions(opts = {}) {
|
|
3631
|
+
const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
|
|
3632
|
+
const files = await listSessionFiles2(root);
|
|
3633
|
+
const out = [];
|
|
3634
|
+
for (const file of files) {
|
|
3635
|
+
const cached = metaCache4.get(file.filePath);
|
|
3636
|
+
if (cached && cached.mtimeMs === file.mtimeMs && cached.sizeBytes === file.sizeBytes && cached.cwd === file.cwd) {
|
|
3637
|
+
out.push(cached.meta);
|
|
3638
|
+
continue;
|
|
3639
|
+
}
|
|
3640
|
+
try {
|
|
3641
|
+
const { meta } = await parseSession2(file);
|
|
3642
|
+
metaCache4.set(file.filePath, {
|
|
3643
|
+
meta,
|
|
3644
|
+
mtimeMs: file.mtimeMs,
|
|
3645
|
+
sizeBytes: file.sizeBytes,
|
|
3646
|
+
cwd: file.cwd
|
|
3647
|
+
});
|
|
3648
|
+
out.push(meta);
|
|
3649
|
+
} catch {
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
out.sort((a, b) => (b.firstTimestamp ?? "").localeCompare(a.firstTimestamp ?? ""));
|
|
3653
|
+
if (opts.limit !== void 0)
|
|
3654
|
+
return out.slice(0, opts.limit);
|
|
3655
|
+
return out;
|
|
3656
|
+
}
|
|
3657
|
+
async function getAntigravitySession(id, opts = {}) {
|
|
3658
|
+
const root = opts.root ?? DEFAULT_ANTIGRAVITY_ROOT;
|
|
3659
|
+
const files = await listSessionFiles2(root);
|
|
3660
|
+
let chosen;
|
|
3661
|
+
for (const file of files) {
|
|
3662
|
+
if (file.conversationId === id) {
|
|
3663
|
+
chosen = file;
|
|
3664
|
+
break;
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
if (!chosen)
|
|
3668
|
+
return null;
|
|
3669
|
+
const cached = detailCache4.get(chosen.filePath);
|
|
3670
|
+
if (cached && cached.mtimeMs === chosen.mtimeMs && cached.sizeBytes === chosen.sizeBytes && cached.cwd === chosen.cwd) {
|
|
3671
|
+
return cached.detail;
|
|
3672
|
+
}
|
|
3673
|
+
const { meta, events } = await parseSession2(chosen);
|
|
3674
|
+
const detail = { ...meta, events };
|
|
3675
|
+
detailCache4.set(chosen.filePath, {
|
|
3676
|
+
detail,
|
|
3677
|
+
mtimeMs: chosen.mtimeMs,
|
|
3678
|
+
sizeBytes: chosen.sizeBytes,
|
|
3679
|
+
cwd: chosen.cwd
|
|
3680
|
+
});
|
|
3681
|
+
return detail;
|
|
3682
|
+
}
|
|
3683
|
+
function antigravitySessionLocalDay(meta) {
|
|
3684
|
+
if (!meta.firstTimestamp)
|
|
3685
|
+
return void 0;
|
|
3686
|
+
const ms = Date.parse(meta.firstTimestamp);
|
|
3687
|
+
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
3688
|
+
}
|
|
3689
|
+
var DEFAULT_ANTIGRAVITY_ROOT, IDLE_GAP_MS3, historyCache, metaCache4, detailCache4;
|
|
3690
|
+
var init_antigravity = __esm({
|
|
3691
|
+
"../parser/dist/antigravity.js"() {
|
|
3692
|
+
"use strict";
|
|
3693
|
+
init_analytics();
|
|
3694
|
+
init_user_input();
|
|
3695
|
+
DEFAULT_ANTIGRAVITY_ROOT = path4.join(os4.homedir(), ".gemini", "antigravity-cli");
|
|
3696
|
+
IDLE_GAP_MS3 = 3 * 60 * 1e3;
|
|
3697
|
+
historyCache = null;
|
|
3698
|
+
metaCache4 = /* @__PURE__ */ new Map();
|
|
3699
|
+
detailCache4 = /* @__PURE__ */ new Map();
|
|
3700
|
+
}
|
|
3701
|
+
});
|
|
3702
|
+
|
|
3703
|
+
// ../parser/dist/cowork.js
|
|
3704
|
+
import { promises as fs5 } from "node:fs";
|
|
3705
|
+
import os5 from "node:os";
|
|
3706
|
+
import path5 from "node:path";
|
|
3707
|
+
function defaultCoworkRoot() {
|
|
3708
|
+
const home = os5.homedir();
|
|
3709
|
+
if (process.platform === "darwin") {
|
|
3710
|
+
return path5.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions");
|
|
3711
|
+
}
|
|
3712
|
+
if (process.platform === "win32") {
|
|
3713
|
+
const appData = process.env.APPDATA ?? path5.join(home, "AppData", "Roaming");
|
|
3714
|
+
return path5.join(appData, "Claude", "local-agent-mode-sessions");
|
|
3715
|
+
}
|
|
3716
|
+
return path5.join(home, ".config", "Claude", "local-agent-mode-sessions");
|
|
3717
|
+
}
|
|
3718
|
+
async function safeReaddir4(p) {
|
|
3719
|
+
return fs5.readdir(p).catch(() => []);
|
|
3720
|
+
}
|
|
3721
|
+
async function statMs(p) {
|
|
3722
|
+
const s = await fs5.stat(p).catch(() => null);
|
|
3723
|
+
return s ? s.mtimeMs : 0;
|
|
3724
|
+
}
|
|
3725
|
+
async function listSessionFiles3(root) {
|
|
3726
|
+
const out = [];
|
|
3727
|
+
const accounts = await safeReaddir4(root);
|
|
3728
|
+
for (const accountId of accounts) {
|
|
3729
|
+
const accountDir = path5.join(root, accountId);
|
|
3730
|
+
const workspaces = await safeReaddir4(accountDir);
|
|
3731
|
+
for (const workspaceId of workspaces) {
|
|
3732
|
+
const workspaceDir = path5.join(accountDir, workspaceId);
|
|
3733
|
+
const spacesMtimeMs = await statMs(path5.join(workspaceDir, "spaces.json"));
|
|
3734
|
+
const entries = await safeReaddir4(workspaceDir);
|
|
3735
|
+
for (const entry of entries) {
|
|
3736
|
+
if (!SESSION_ID_RE.test(entry))
|
|
3737
|
+
continue;
|
|
3738
|
+
const auditPath = path5.join(workspaceDir, entry, "audit.jsonl");
|
|
3739
|
+
const auditStat = await fs5.stat(auditPath).catch(() => null);
|
|
3740
|
+
if (!auditStat || !auditStat.isFile() || auditStat.size === 0)
|
|
3741
|
+
continue;
|
|
3742
|
+
const metaPath = path5.join(workspaceDir, `${entry}.json`);
|
|
3743
|
+
const metaMtimeMs = await statMs(metaPath);
|
|
3744
|
+
out.push({
|
|
3745
|
+
sessionId: entry,
|
|
3746
|
+
auditPath,
|
|
3747
|
+
metaPath,
|
|
3748
|
+
workspaceDir,
|
|
3749
|
+
auditMtimeMs: auditStat.mtimeMs,
|
|
3750
|
+
auditSize: auditStat.size,
|
|
3751
|
+
metaMtimeMs,
|
|
3752
|
+
spacesMtimeMs
|
|
3753
|
+
});
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
return out;
|
|
3758
|
+
}
|
|
3759
|
+
async function loadSpacesForWorkspace(workspaceDir) {
|
|
3760
|
+
const spacesPath = path5.join(workspaceDir, "spaces.json");
|
|
3761
|
+
const stat = await fs5.stat(spacesPath).catch(() => null);
|
|
3762
|
+
if (!stat)
|
|
3763
|
+
return /* @__PURE__ */ new Map();
|
|
3764
|
+
const cached = spacesCache.get(workspaceDir);
|
|
3765
|
+
if (cached && cached.mtimeMs === stat.mtimeMs)
|
|
3766
|
+
return cached.spaceIdToPath;
|
|
3767
|
+
const raw = await fs5.readFile(spacesPath, "utf8").catch(() => "");
|
|
3768
|
+
const out = /* @__PURE__ */ new Map();
|
|
3769
|
+
try {
|
|
3770
|
+
const parsed = JSON.parse(raw);
|
|
3771
|
+
for (const space of parsed.spaces ?? []) {
|
|
3772
|
+
const id = typeof space.id === "string" ? space.id : void 0;
|
|
3773
|
+
const folders = Array.isArray(space.folders) ? space.folders : [];
|
|
3774
|
+
const first = folders[0];
|
|
3775
|
+
const folderPath = typeof first?.path === "string" ? first.path : void 0;
|
|
3776
|
+
if (id && folderPath)
|
|
3777
|
+
out.set(id, folderPath);
|
|
3778
|
+
}
|
|
3779
|
+
} catch {
|
|
3780
|
+
}
|
|
3781
|
+
spacesCache.set(workspaceDir, { mtimeMs: stat.mtimeMs, spaceIdToPath: out });
|
|
3782
|
+
return out;
|
|
3783
|
+
}
|
|
3784
|
+
async function readCoworkMeta(metaPath) {
|
|
3785
|
+
const raw = await fs5.readFile(metaPath, "utf8").catch(() => "");
|
|
3786
|
+
if (!raw)
|
|
3787
|
+
return {};
|
|
3788
|
+
try {
|
|
3789
|
+
const j = JSON.parse(raw);
|
|
3790
|
+
return {
|
|
3791
|
+
spaceId: typeof j.spaceId === "string" ? j.spaceId : void 0,
|
|
3792
|
+
userSelectedFolders: Array.isArray(j.userSelectedFolders) ? j.userSelectedFolders.filter((s) => typeof s === "string") : void 0,
|
|
3793
|
+
cwd: typeof j.cwd === "string" ? j.cwd : void 0,
|
|
3794
|
+
model: typeof j.model === "string" ? j.model : void 0,
|
|
3795
|
+
title: typeof j.title === "string" ? j.title : void 0,
|
|
3796
|
+
createdAt: typeof j.createdAt === "number" ? j.createdAt : void 0,
|
|
3797
|
+
lastActivityAt: typeof j.lastActivityAt === "number" ? j.lastActivityAt : void 0
|
|
3798
|
+
};
|
|
3799
|
+
} catch {
|
|
3800
|
+
return {};
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
function resolveProject(meta, spaceIdToPath) {
|
|
3804
|
+
let projectPath;
|
|
3805
|
+
if (meta.spaceId)
|
|
3806
|
+
projectPath = spaceIdToPath.get(meta.spaceId);
|
|
3807
|
+
if (!projectPath && meta.userSelectedFolders && meta.userSelectedFolders.length > 0) {
|
|
3808
|
+
projectPath = meta.userSelectedFolders[0];
|
|
3809
|
+
}
|
|
3810
|
+
if (!projectPath) {
|
|
3811
|
+
return { projectName: "cowork:unspaced", projectDir: "cowork-unspaced" };
|
|
3812
|
+
}
|
|
3813
|
+
return {
|
|
3814
|
+
projectName: canonicalProjectName(projectPath),
|
|
3815
|
+
projectDir: projectPath.replace(/^\//, "-").replace(/\//g, "-"),
|
|
3816
|
+
cwd: projectPath
|
|
3817
|
+
};
|
|
3818
|
+
}
|
|
3819
|
+
async function readJsonl2(filePath) {
|
|
3820
|
+
const raw = await fs5.readFile(filePath, "utf8");
|
|
3821
|
+
const out = [];
|
|
3822
|
+
for (const line of raw.split("\n")) {
|
|
3823
|
+
const trimmed = line.trim();
|
|
3824
|
+
if (!trimmed)
|
|
3825
|
+
continue;
|
|
3826
|
+
try {
|
|
3827
|
+
out.push(JSON.parse(trimmed));
|
|
3828
|
+
} catch {
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3831
|
+
return out;
|
|
3832
|
+
}
|
|
3833
|
+
async function parseCoworkSession(file) {
|
|
3834
|
+
const [lines, coworkMeta, spaceIdToPath] = await Promise.all([
|
|
3835
|
+
readJsonl2(file.auditPath),
|
|
3836
|
+
readCoworkMeta(file.metaPath),
|
|
3837
|
+
loadSpacesForWorkspace(file.workspaceDir)
|
|
3838
|
+
]);
|
|
3839
|
+
const { meta: baseMeta, events } = parseTranscript(lines);
|
|
3840
|
+
const { projectName, projectDir, cwd } = resolveProject(coworkMeta, spaceIdToPath);
|
|
2847
3841
|
const meta = {
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
3842
|
+
...baseMeta,
|
|
3843
|
+
agent: "cowork",
|
|
3844
|
+
id: file.sessionId,
|
|
3845
|
+
sessionId: file.sessionId,
|
|
3846
|
+
filePath: file.auditPath,
|
|
2851
3847
|
projectName,
|
|
2852
3848
|
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
|
|
3849
|
+
cwd: cwd ?? baseMeta.cwd,
|
|
3850
|
+
model: baseMeta.model ?? coworkMeta.model
|
|
2869
3851
|
};
|
|
2870
3852
|
return { meta, events };
|
|
2871
3853
|
}
|
|
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;
|
|
3854
|
+
function cacheKeyFor(file) {
|
|
3855
|
+
return {
|
|
3856
|
+
auditMtimeMs: file.auditMtimeMs,
|
|
3857
|
+
auditSize: file.auditSize,
|
|
3858
|
+
metaMtimeMs: file.metaMtimeMs,
|
|
3859
|
+
spacesMtimeMs: file.spacesMtimeMs
|
|
3860
|
+
};
|
|
2888
3861
|
}
|
|
2889
|
-
function
|
|
2890
|
-
|
|
2891
|
-
detailCache3.clear();
|
|
2892
|
-
projectsCache = null;
|
|
3862
|
+
function cacheKeyMatches(a, b) {
|
|
3863
|
+
return a.auditMtimeMs === b.auditMtimeMs && a.auditSize === b.auditSize && a.metaMtimeMs === b.metaMtimeMs && a.spacesMtimeMs === b.spacesMtimeMs;
|
|
2893
3864
|
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3865
|
+
function clearCoworkCaches() {
|
|
3866
|
+
metaCache5.clear();
|
|
3867
|
+
detailCache5.clear();
|
|
3868
|
+
spacesCache.clear();
|
|
3869
|
+
}
|
|
3870
|
+
async function listCoworkSessions(opts = {}) {
|
|
3871
|
+
const root = opts.root ?? DEFAULT_COWORK_ROOT;
|
|
3872
|
+
const files = await listSessionFiles3(root);
|
|
2897
3873
|
const out = [];
|
|
2898
3874
|
for (const file of files) {
|
|
2899
|
-
const
|
|
2900
|
-
|
|
3875
|
+
const key = cacheKeyFor(file);
|
|
3876
|
+
const cached = metaCache5.get(file.auditPath);
|
|
3877
|
+
if (cached && cacheKeyMatches(cached.key, key)) {
|
|
2901
3878
|
out.push(cached.meta);
|
|
2902
3879
|
continue;
|
|
2903
3880
|
}
|
|
2904
3881
|
try {
|
|
2905
|
-
const { meta } = await
|
|
2906
|
-
|
|
2907
|
-
meta,
|
|
2908
|
-
mtimeMs: file.mtimeMs,
|
|
2909
|
-
sizeBytes: file.sizeBytes
|
|
2910
|
-
});
|
|
3882
|
+
const { meta } = await parseCoworkSession(file);
|
|
3883
|
+
metaCache5.set(file.auditPath, { meta, key });
|
|
2911
3884
|
out.push(meta);
|
|
2912
3885
|
} catch {
|
|
2913
3886
|
}
|
|
@@ -2917,59 +3890,38 @@ async function listGeminiSessions(opts = {}) {
|
|
|
2917
3890
|
return out.slice(0, opts.limit);
|
|
2918
3891
|
return out;
|
|
2919
3892
|
}
|
|
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)
|
|
3893
|
+
async function getCoworkSession(id, opts = {}) {
|
|
3894
|
+
const root = opts.root ?? DEFAULT_COWORK_ROOT;
|
|
3895
|
+
const files = await listSessionFiles3(root);
|
|
3896
|
+
const file = files.find((f) => f.sessionId === id);
|
|
3897
|
+
if (!file)
|
|
2940
3898
|
return null;
|
|
2941
|
-
const
|
|
2942
|
-
|
|
3899
|
+
const key = cacheKeyFor(file);
|
|
3900
|
+
const cached = detailCache5.get(file.auditPath);
|
|
3901
|
+
if (cached && cacheKeyMatches(cached.key, key))
|
|
2943
3902
|
return cached.detail;
|
|
2944
|
-
}
|
|
2945
|
-
const { meta, events } = await parseSession(chosen);
|
|
3903
|
+
const { meta, events } = await parseCoworkSession(file);
|
|
2946
3904
|
const detail = { ...meta, events };
|
|
2947
|
-
|
|
2948
|
-
detail,
|
|
2949
|
-
mtimeMs: chosen.mtimeMs,
|
|
2950
|
-
sizeBytes: chosen.sizeBytes
|
|
2951
|
-
});
|
|
3905
|
+
detailCache5.set(file.auditPath, { detail, key });
|
|
2952
3906
|
return detail;
|
|
2953
3907
|
}
|
|
2954
|
-
function
|
|
3908
|
+
function coworkSessionLocalDay(meta) {
|
|
2955
3909
|
if (!meta.firstTimestamp)
|
|
2956
3910
|
return void 0;
|
|
2957
3911
|
const ms = Date.parse(meta.firstTimestamp);
|
|
2958
3912
|
return Number.isFinite(ms) ? toLocalDay(ms) : void 0;
|
|
2959
3913
|
}
|
|
2960
|
-
var
|
|
2961
|
-
var
|
|
2962
|
-
"../parser/dist/
|
|
3914
|
+
var DEFAULT_COWORK_ROOT, SESSION_ID_RE, spacesCache, metaCache5, detailCache5;
|
|
3915
|
+
var init_cowork = __esm({
|
|
3916
|
+
"../parser/dist/cowork.js"() {
|
|
2963
3917
|
"use strict";
|
|
2964
3918
|
init_analytics();
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
metaCache3 = /* @__PURE__ */ new Map();
|
|
2972
|
-
detailCache3 = /* @__PURE__ */ new Map();
|
|
3919
|
+
init_parser();
|
|
3920
|
+
DEFAULT_COWORK_ROOT = defaultCoworkRoot();
|
|
3921
|
+
SESSION_ID_RE = /^local_[0-9a-f-]+$/;
|
|
3922
|
+
spacesCache = /* @__PURE__ */ new Map();
|
|
3923
|
+
metaCache5 = /* @__PURE__ */ new Map();
|
|
3924
|
+
detailCache5 = /* @__PURE__ */ new Map();
|
|
2973
3925
|
}
|
|
2974
3926
|
});
|
|
2975
3927
|
|
|
@@ -3017,11 +3969,14 @@ var init_team_wire = __esm({
|
|
|
3017
3969
|
// ../parser/dist/fs.js
|
|
3018
3970
|
var fs_exports = {};
|
|
3019
3971
|
__export(fs_exports, {
|
|
3972
|
+
DEFAULT_ANTIGRAVITY_ROOT: () => DEFAULT_ANTIGRAVITY_ROOT,
|
|
3020
3973
|
DEFAULT_CODEX_ROOT: () => DEFAULT_CODEX_ROOT,
|
|
3974
|
+
DEFAULT_COWORK_ROOT: () => DEFAULT_COWORK_ROOT,
|
|
3021
3975
|
DEFAULT_GEMINI_ROOT: () => DEFAULT_GEMINI_ROOT,
|
|
3022
3976
|
DEFAULT_ROOT: () => DEFAULT_ROOT,
|
|
3023
3977
|
RICH_ROLLUP_SCHEMA_VERSION: () => RICH_ROLLUP_SCHEMA_VERSION,
|
|
3024
3978
|
agentSources: () => agentSources,
|
|
3979
|
+
antigravitySessionLocalDay: () => antigravitySessionLocalDay,
|
|
3025
3980
|
buildCalibrationCurve: () => buildCalibrationCurve,
|
|
3026
3981
|
cacheStats: () => cacheStats,
|
|
3027
3982
|
cclensHome: () => cclensHome,
|
|
@@ -3029,19 +3984,24 @@ __export(fs_exports, {
|
|
|
3029
3984
|
clearCaches: () => clearCaches,
|
|
3030
3985
|
clearTeamConfig: () => clearTeamConfig,
|
|
3031
3986
|
codexSessionLocalDay: () => codexSessionLocalDay,
|
|
3987
|
+
coworkSessionLocalDay: () => coworkSessionLocalDay,
|
|
3032
3988
|
decodeProjectName: () => decodeProjectName,
|
|
3033
3989
|
findTeamLead: () => findTeamLead,
|
|
3034
3990
|
geminiSessionLocalDay: () => geminiSessionLocalDay,
|
|
3035
3991
|
getAgentSource: () => getAgentSource,
|
|
3992
|
+
getAntigravitySession: () => getAntigravitySession,
|
|
3036
3993
|
getAnySession: () => getAnySession,
|
|
3037
3994
|
getCodexSession: () => getCodexSession,
|
|
3995
|
+
getCoworkSession: () => getCoworkSession,
|
|
3038
3996
|
getGeminiSession: () => getGeminiSession,
|
|
3039
3997
|
getLatestCodexUsage: () => getLatestCodexUsage,
|
|
3040
3998
|
getSession: () => getSession,
|
|
3041
3999
|
invalidateFile: () => invalidateFile,
|
|
3042
4000
|
isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
|
|
3043
4001
|
listAllSessions: () => listAllSessions,
|
|
4002
|
+
listAntigravitySessions: () => listAntigravitySessions,
|
|
3044
4003
|
listCodexSessions: () => listCodexSessions,
|
|
4004
|
+
listCoworkSessions: () => listCoworkSessions,
|
|
3045
4005
|
listGeminiSessions: () => listGeminiSessions,
|
|
3046
4006
|
listProjects: () => listProjects,
|
|
3047
4007
|
listSessions: () => listSessions,
|
|
@@ -3050,20 +4010,21 @@ __export(fs_exports, {
|
|
|
3050
4010
|
loadCalibrationSnapshots: () => loadCalibrationSnapshots,
|
|
3051
4011
|
loadTeamForSession: () => loadTeamForSession,
|
|
3052
4012
|
loadUsageByDay: () => loadUsageByDay,
|
|
4013
|
+
loadWorkflowAgentDetail: () => loadWorkflowAgentDetail,
|
|
3053
4014
|
readJsonlFile: () => readJsonlFile,
|
|
3054
4015
|
readTeamConfig: () => readTeamConfig,
|
|
3055
4016
|
sessionIdFromFileName: () => sessionIdFromFileName,
|
|
3056
4017
|
walkJsonlFiles: () => walkJsonlFiles,
|
|
3057
4018
|
writeTeamConfig: () => writeTeamConfig
|
|
3058
4019
|
});
|
|
3059
|
-
import { promises as
|
|
3060
|
-
import
|
|
3061
|
-
import
|
|
4020
|
+
import { promises as fs6 } from "node:fs";
|
|
4021
|
+
import os6 from "node:os";
|
|
4022
|
+
import path6 from "node:path";
|
|
3062
4023
|
function cclensHome() {
|
|
3063
|
-
return process.env.CCLENS_HOME ||
|
|
4024
|
+
return process.env.CCLENS_HOME || path6.join(os6.homedir(), ".cclens");
|
|
3064
4025
|
}
|
|
3065
4026
|
function cclensPath(...parts) {
|
|
3066
|
-
return
|
|
4027
|
+
return path6.join(cclensHome(), ...parts);
|
|
3067
4028
|
}
|
|
3068
4029
|
function cacheStats() {
|
|
3069
4030
|
return claudeCodeCacheStats();
|
|
@@ -3072,6 +4033,8 @@ function clearCaches() {
|
|
|
3072
4033
|
clearClaudeCodeCaches();
|
|
3073
4034
|
clearCodexCaches();
|
|
3074
4035
|
clearGeminiCaches();
|
|
4036
|
+
clearAntigravityCaches();
|
|
4037
|
+
clearCoworkCaches();
|
|
3075
4038
|
}
|
|
3076
4039
|
function invalidateFile(fullPath) {
|
|
3077
4040
|
invalidateClaudeCodeFile(fullPath);
|
|
@@ -3103,7 +4066,7 @@ function usageLogPath() {
|
|
|
3103
4066
|
async function loadUsageByDay(start, end) {
|
|
3104
4067
|
let raw;
|
|
3105
4068
|
try {
|
|
3106
|
-
raw = await
|
|
4069
|
+
raw = await fs6.readFile(usageLogPath(), "utf8");
|
|
3107
4070
|
} catch {
|
|
3108
4071
|
return { by_day: [] };
|
|
3109
4072
|
}
|
|
@@ -3148,7 +4111,7 @@ async function loadUsageByDay(start, end) {
|
|
|
3148
4111
|
async function loadCalibrationSnapshots() {
|
|
3149
4112
|
let raw;
|
|
3150
4113
|
try {
|
|
3151
|
-
raw = await
|
|
4114
|
+
raw = await fs6.readFile(usageLogPath(), "utf8");
|
|
3152
4115
|
} catch {
|
|
3153
4116
|
return [];
|
|
3154
4117
|
}
|
|
@@ -3306,7 +4269,7 @@ async function loadCalibrationCurve(tier = "pro-max-20x", root = DEFAULT_ROOT, g
|
|
|
3306
4269
|
]);
|
|
3307
4270
|
return buildCalibrationCurve(events, snapshots, tier, granularityMin);
|
|
3308
4271
|
}
|
|
3309
|
-
var codexSource, geminiSource, agentSources;
|
|
4272
|
+
var codexSource, geminiSource, antigravitySource, coworkSource, agentSources;
|
|
3310
4273
|
var init_fs = __esm({
|
|
3311
4274
|
"../parser/dist/fs.js"() {
|
|
3312
4275
|
"use strict";
|
|
@@ -3316,9 +4279,13 @@ var init_fs = __esm({
|
|
|
3316
4279
|
init_claude_code();
|
|
3317
4280
|
init_codex();
|
|
3318
4281
|
init_gemini();
|
|
4282
|
+
init_antigravity();
|
|
4283
|
+
init_cowork();
|
|
3319
4284
|
init_claude_code();
|
|
3320
4285
|
init_codex();
|
|
3321
4286
|
init_gemini();
|
|
4287
|
+
init_antigravity();
|
|
4288
|
+
init_cowork();
|
|
3322
4289
|
init_team_config();
|
|
3323
4290
|
init_team_wire();
|
|
3324
4291
|
codexSource = {
|
|
@@ -3352,7 +4319,33 @@ var init_fs = __esm({
|
|
|
3352
4319
|
return getGeminiSession(id);
|
|
3353
4320
|
}
|
|
3354
4321
|
};
|
|
3355
|
-
|
|
4322
|
+
antigravitySource = {
|
|
4323
|
+
...ANTIGRAVITY_METADATA,
|
|
4324
|
+
defaultRoot: DEFAULT_ANTIGRAVITY_ROOT,
|
|
4325
|
+
async listSessions(opts) {
|
|
4326
|
+
return listAntigravitySessions(opts);
|
|
4327
|
+
},
|
|
4328
|
+
async getSession(id) {
|
|
4329
|
+
return getAntigravitySession(id);
|
|
4330
|
+
}
|
|
4331
|
+
};
|
|
4332
|
+
coworkSource = {
|
|
4333
|
+
...COWORK_METADATA,
|
|
4334
|
+
defaultRoot: DEFAULT_COWORK_ROOT,
|
|
4335
|
+
async listSessions(opts) {
|
|
4336
|
+
return listCoworkSessions(opts);
|
|
4337
|
+
},
|
|
4338
|
+
async getSession(id) {
|
|
4339
|
+
return getCoworkSession(id);
|
|
4340
|
+
}
|
|
4341
|
+
};
|
|
4342
|
+
agentSources = [
|
|
4343
|
+
claudeCodeSource,
|
|
4344
|
+
codexSource,
|
|
4345
|
+
geminiSource,
|
|
4346
|
+
antigravitySource,
|
|
4347
|
+
coworkSource
|
|
4348
|
+
];
|
|
3356
4349
|
}
|
|
3357
4350
|
});
|
|
3358
4351
|
|
|
@@ -3764,8 +4757,10 @@ var init_aggregate = __esm({
|
|
|
3764
4757
|
// ../parser/dist/index.js
|
|
3765
4758
|
var dist_exports = {};
|
|
3766
4759
|
__export(dist_exports, {
|
|
4760
|
+
ANTIGRAVITY_METADATA: () => ANTIGRAVITY_METADATA,
|
|
3767
4761
|
CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
|
|
3768
4762
|
CODEX_METADATA: () => CODEX_METADATA,
|
|
4763
|
+
COWORK_METADATA: () => COWORK_METADATA,
|
|
3769
4764
|
GEMINI_METADATA: () => GEMINI_METADATA,
|
|
3770
4765
|
PRICES: () => PRICES,
|
|
3771
4766
|
RATE_PER_PCT: () => RATE_PER_PCT,
|
|
@@ -3806,6 +4801,7 @@ __export(dist_exports, {
|
|
|
3806
4801
|
predictUtilization: () => predictUtilization,
|
|
3807
4802
|
priorCalendarMonth: () => priorCalendarMonth,
|
|
3808
4803
|
priorCalendarWeek: () => priorCalendarWeek,
|
|
4804
|
+
projectRepoName: () => projectRepoName,
|
|
3809
4805
|
rowPrimaryIndex: () => rowPrimaryIndex,
|
|
3810
4806
|
sessionAirTimeMs: () => sessionAirTimeMs,
|
|
3811
4807
|
sessionDay: () => sessionDay,
|
|
@@ -3830,10 +4826,198 @@ var init_dist = __esm({
|
|
|
3830
4826
|
}
|
|
3831
4827
|
});
|
|
3832
4828
|
|
|
4829
|
+
// src/perception/file-probe.ts
|
|
4830
|
+
var file_probe_exports = {};
|
|
4831
|
+
__export(file_probe_exports, {
|
|
4832
|
+
pathHash: () => pathHash,
|
|
4833
|
+
probeArtifactSignals: () => probeArtifactSignals
|
|
4834
|
+
});
|
|
4835
|
+
import { createHash } from "node:crypto";
|
|
4836
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
|
|
4837
|
+
import { homedir as homedir2 } from "node:os";
|
|
4838
|
+
import { join as join7, relative, resolve as resolve2, sep } from "node:path";
|
|
4839
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
4840
|
+
function pathHash(relPath) {
|
|
4841
|
+
return createHash("sha256").update(relPath.split(sep).join("/")).digest("hex").slice(0, 32);
|
|
4842
|
+
}
|
|
4843
|
+
function defaultScanRoots(extraRoots = []) {
|
|
4844
|
+
const roots = [];
|
|
4845
|
+
const home = join7(homedir2(), ".claude");
|
|
4846
|
+
if (existsSync6(home)) roots.push({ root: home, label: "user" });
|
|
4847
|
+
for (const e of extraRoots) {
|
|
4848
|
+
const r = resolve2(e, ".claude");
|
|
4849
|
+
if (existsSync6(r) && r !== home) roots.push({ root: r, label: "project" });
|
|
4850
|
+
}
|
|
4851
|
+
return roots;
|
|
4852
|
+
}
|
|
4853
|
+
function listMarkdownFiles(dir) {
|
|
4854
|
+
if (!existsSync6(dir)) return [];
|
|
4855
|
+
const out = [];
|
|
4856
|
+
let entries;
|
|
4857
|
+
try {
|
|
4858
|
+
entries = readdirSync3(dir);
|
|
4859
|
+
} catch {
|
|
4860
|
+
return [];
|
|
4861
|
+
}
|
|
4862
|
+
for (const name of entries) {
|
|
4863
|
+
if (name.startsWith(".")) continue;
|
|
4864
|
+
const full = join7(dir, name);
|
|
4865
|
+
let stat;
|
|
4866
|
+
try {
|
|
4867
|
+
stat = statSync3(full);
|
|
4868
|
+
} catch {
|
|
4869
|
+
continue;
|
|
4870
|
+
}
|
|
4871
|
+
if (stat.isDirectory()) {
|
|
4872
|
+
out.push(...listMarkdownFiles(full));
|
|
4873
|
+
} else if (stat.isFile() && name.endsWith(".md")) {
|
|
4874
|
+
out.push(full);
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return out;
|
|
4878
|
+
}
|
|
4879
|
+
function firstSeenDateOf(file) {
|
|
4880
|
+
try {
|
|
4881
|
+
const out = execFileSync2(
|
|
4882
|
+
"git",
|
|
4883
|
+
["log", "--diff-filter=A", "--follow", "--format=%cs", "--", file],
|
|
4884
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname6(file) }
|
|
4885
|
+
).trim().split("\n").filter(Boolean);
|
|
4886
|
+
if (out.length > 0) return out[out.length - 1];
|
|
4887
|
+
} catch {
|
|
4888
|
+
}
|
|
4889
|
+
try {
|
|
4890
|
+
const s = statSync3(file);
|
|
4891
|
+
return new Date((s.birthtime || s.mtime).getTime()).toISOString().slice(0, 10);
|
|
4892
|
+
} catch {
|
|
4893
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4896
|
+
function dirname6(p) {
|
|
4897
|
+
const i = p.lastIndexOf(sep);
|
|
4898
|
+
return i < 0 ? "." : p.slice(0, i);
|
|
4899
|
+
}
|
|
4900
|
+
function detectGitEmail(cwd) {
|
|
4901
|
+
try {
|
|
4902
|
+
return execFileSync2("git", ["config", "user.email"], {
|
|
4903
|
+
encoding: "utf8",
|
|
4904
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4905
|
+
cwd
|
|
4906
|
+
}).trim() || null;
|
|
4907
|
+
} catch {
|
|
4908
|
+
return null;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
function todayLocal() {
|
|
4912
|
+
const d = /* @__PURE__ */ new Date();
|
|
4913
|
+
const y = d.getFullYear();
|
|
4914
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
4915
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
4916
|
+
return `${y}-${m}-${day}`;
|
|
4917
|
+
}
|
|
4918
|
+
function scanAuthored(roots, subdir, day) {
|
|
4919
|
+
const out = [];
|
|
4920
|
+
for (const r of roots) {
|
|
4921
|
+
const dir = join7(r.root, subdir);
|
|
4922
|
+
if (!existsSync6(dir)) continue;
|
|
4923
|
+
for (const f of listMarkdownFiles(dir)) {
|
|
4924
|
+
const firstSeen = firstSeenDateOf(f);
|
|
4925
|
+
if (firstSeen !== day) continue;
|
|
4926
|
+
const rel = relative(dir, f);
|
|
4927
|
+
out.push({ pathHash: pathHash(`${r.label}:${subdir}:${rel}`), firstSeenDate: firstSeen });
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
return out;
|
|
4931
|
+
}
|
|
4932
|
+
function scanEdited(roots, day) {
|
|
4933
|
+
const out = [];
|
|
4934
|
+
for (const r of roots) {
|
|
4935
|
+
const dir = join7(r.root, "skills");
|
|
4936
|
+
if (!existsSync6(dir)) continue;
|
|
4937
|
+
for (const f of listMarkdownFiles(dir)) {
|
|
4938
|
+
const firstSeen = firstSeenDateOf(f);
|
|
4939
|
+
if (firstSeen === day) continue;
|
|
4940
|
+
let stat;
|
|
4941
|
+
try {
|
|
4942
|
+
stat = statSync3(f);
|
|
4943
|
+
} catch {
|
|
4944
|
+
continue;
|
|
4945
|
+
}
|
|
4946
|
+
const mtimeDay = new Date(stat.mtime.getTime()).toISOString().slice(0, 10);
|
|
4947
|
+
if (mtimeDay !== day) continue;
|
|
4948
|
+
const rel = relative(dir, f);
|
|
4949
|
+
out.push({ pathHash: pathHash(`${r.label}:skills:${rel}`), lineDelta: 0 });
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
return out;
|
|
4953
|
+
}
|
|
4954
|
+
function claudemdLineDelta(extraRoots, authorEmail, day) {
|
|
4955
|
+
let delta = 0;
|
|
4956
|
+
const candidates = [];
|
|
4957
|
+
for (const e of extraRoots) {
|
|
4958
|
+
const f = resolve2(e, "CLAUDE.md");
|
|
4959
|
+
if (existsSync6(f)) candidates.push(f);
|
|
4960
|
+
}
|
|
4961
|
+
const homeClaudeMd = join7(homedir2(), "CLAUDE.md");
|
|
4962
|
+
if (existsSync6(homeClaudeMd)) candidates.push(homeClaudeMd);
|
|
4963
|
+
for (const file of candidates) {
|
|
4964
|
+
try {
|
|
4965
|
+
const out = execFileSync2(
|
|
4966
|
+
"git",
|
|
4967
|
+
["log", "--numstat", "--format=COMMIT %cs %ae", "--", file],
|
|
4968
|
+
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], cwd: dirname6(file) }
|
|
4969
|
+
);
|
|
4970
|
+
let currentDate = "";
|
|
4971
|
+
let currentEmail = "";
|
|
4972
|
+
for (const line of out.split("\n")) {
|
|
4973
|
+
if (line.startsWith("COMMIT ")) {
|
|
4974
|
+
const parts = line.slice("COMMIT ".length).trim().split(/\s+/);
|
|
4975
|
+
currentDate = parts[0] ?? "";
|
|
4976
|
+
currentEmail = parts.slice(1).join(" ");
|
|
4977
|
+
} else if (currentDate === day && line.trim().length > 0) {
|
|
4978
|
+
if (authorEmail && currentEmail !== authorEmail) continue;
|
|
4979
|
+
const parts = line.split(/\s+/);
|
|
4980
|
+
const added = Number(parts[0]);
|
|
4981
|
+
const removed = Number(parts[1]);
|
|
4982
|
+
if (Number.isFinite(added) && Number.isFinite(removed)) {
|
|
4983
|
+
delta += added - removed;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
} catch {
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
return delta;
|
|
4991
|
+
}
|
|
4992
|
+
function probeArtifactSignals(opts = {}) {
|
|
4993
|
+
const day = opts.day ?? todayLocal();
|
|
4994
|
+
const roots = defaultScanRoots(opts.extraRoots);
|
|
4995
|
+
const skillsAuthored = scanAuthored(roots, "skills", day);
|
|
4996
|
+
const subagentsAuthored = scanAuthored(roots, "agents", day);
|
|
4997
|
+
const slashCommandsAuthored = scanAuthored(roots, "commands", day);
|
|
4998
|
+
const skillsEdited = scanEdited(roots, day);
|
|
4999
|
+
const authorEmail = opts.authorEmail ?? detectGitEmail(opts.extraRoots?.[0] ?? process.cwd()) ?? void 0;
|
|
5000
|
+
const claudemd = claudemdLineDelta(opts.extraRoots ?? [], authorEmail, day);
|
|
5001
|
+
const empty = skillsAuthored.length === 0 && subagentsAuthored.length === 0 && slashCommandsAuthored.length === 0 && skillsEdited.length === 0 && claudemd === 0;
|
|
5002
|
+
if (empty) return null;
|
|
5003
|
+
return {
|
|
5004
|
+
skillsAuthored,
|
|
5005
|
+
skillsEdited,
|
|
5006
|
+
subagentsAuthored,
|
|
5007
|
+
slashCommandsAuthored,
|
|
5008
|
+
claudemdLineDelta: claudemd
|
|
5009
|
+
};
|
|
5010
|
+
}
|
|
5011
|
+
var init_file_probe = __esm({
|
|
5012
|
+
"src/perception/file-probe.ts"() {
|
|
5013
|
+
"use strict";
|
|
5014
|
+
}
|
|
5015
|
+
});
|
|
5016
|
+
|
|
3833
5017
|
// src/daemon-worker.ts
|
|
3834
5018
|
import { spawn as spawn2 } from "node:child_process";
|
|
3835
|
-
import { appendFileSync as appendFileSync5, closeSync, existsSync as
|
|
3836
|
-
import { dirname as
|
|
5019
|
+
import { appendFileSync as appendFileSync5, closeSync, existsSync as existsSync13, mkdirSync as mkdirSync13, openSync, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "node:fs";
|
|
5020
|
+
import { dirname as dirname10, join as join11 } from "node:path";
|
|
3837
5021
|
import { fileURLToPath } from "node:url";
|
|
3838
5022
|
|
|
3839
5023
|
// src/usage/token.ts
|
|
@@ -3864,9 +5048,9 @@ function readFromCredentialsFile() {
|
|
|
3864
5048
|
join(homedir(), ".claude", ".credentials.json"),
|
|
3865
5049
|
join(homedir(), ".config", "claude", "credentials.json")
|
|
3866
5050
|
];
|
|
3867
|
-
for (const
|
|
5051
|
+
for (const path7 of candidates) {
|
|
3868
5052
|
try {
|
|
3869
|
-
const blob = readFileSync(
|
|
5053
|
+
const blob = readFileSync(path7, "utf8");
|
|
3870
5054
|
const creds = extractCredentials(blob);
|
|
3871
5055
|
if (creds) return creds;
|
|
3872
5056
|
} catch {
|
|
@@ -4322,7 +5506,7 @@ function sessionTouchesDay(s, day) {
|
|
|
4322
5506
|
}
|
|
4323
5507
|
return sessionDay(s) === day;
|
|
4324
5508
|
}
|
|
4325
|
-
function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
5509
|
+
function buildRichRollupBlocks(day, daySessions, entries, privateProjects, resolveRepo) {
|
|
4326
5510
|
const bounds = dayBoundsMs(day);
|
|
4327
5511
|
const clippedSessions = [];
|
|
4328
5512
|
for (const s of daySessions) {
|
|
@@ -4332,16 +5516,40 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4332
5516
|
}
|
|
4333
5517
|
const bursts = computeBurstsFromSessions(clippedSessions);
|
|
4334
5518
|
const stats = summarizeBursts(bursts);
|
|
5519
|
+
const repoForEntry = (e) => {
|
|
5520
|
+
if (resolveRepo) {
|
|
5521
|
+
const own = resolveRepo(e.project);
|
|
5522
|
+
if (own) return own;
|
|
5523
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5524
|
+
for (const d of e.edited_dirs ?? []) {
|
|
5525
|
+
const r = resolveRepo(d);
|
|
5526
|
+
if (r) counts.set(r, (counts.get(r) ?? 0) + 1);
|
|
5527
|
+
}
|
|
5528
|
+
const dominant = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
5529
|
+
if (dominant) return dominant;
|
|
5530
|
+
}
|
|
5531
|
+
return e.github_repos?.length === 1 ? e.github_repos[0] : null;
|
|
5532
|
+
};
|
|
5533
|
+
const sessionRepo = /* @__PURE__ */ new Map();
|
|
5534
|
+
for (const e of entries) {
|
|
5535
|
+
if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
|
|
5536
|
+
const r = repoForEntry(e);
|
|
5537
|
+
if (r) sessionRepo.set(e.session_id, r);
|
|
5538
|
+
}
|
|
4335
5539
|
const projects = /* @__PURE__ */ new Map();
|
|
4336
5540
|
for (const s of clippedSessions) {
|
|
4337
|
-
const
|
|
4338
|
-
|
|
5541
|
+
const canonical = canonicalProjectName(s.projectName);
|
|
5542
|
+
const name = projectRepoName(s.projectName);
|
|
5543
|
+
if (privateProjects.has(name) || privateProjects.has(canonical)) continue;
|
|
5544
|
+
const repo = resolveRepo?.(canonical) ?? sessionRepo.get(s.id);
|
|
5545
|
+
const key = repo ?? name;
|
|
4339
5546
|
const ms = s.activeSegments.reduce((sum, seg) => sum + (seg.endMs - seg.startMs), 0);
|
|
4340
|
-
const cur = projects.get(
|
|
5547
|
+
const cur = projects.get(key) ?? { project: name, agentTimeMs: 0, sessions: 0, ...repo ? { resolved: repo } : {} };
|
|
4341
5548
|
cur.agentTimeMs += ms;
|
|
4342
5549
|
cur.sessions += 1;
|
|
4343
|
-
projects.set(
|
|
5550
|
+
projects.set(key, cur);
|
|
4344
5551
|
}
|
|
5552
|
+
const projectRepos = /* @__PURE__ */ new Map();
|
|
4345
5553
|
const workingShapes = /* @__PURE__ */ new Map();
|
|
4346
5554
|
const skills = /* @__PURE__ */ new Map();
|
|
4347
5555
|
const subagents = /* @__PURE__ */ new Map();
|
|
@@ -4355,12 +5563,12 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4355
5563
|
let longTotalMin = 0;
|
|
4356
5564
|
let longMaxSingleMin = 0;
|
|
4357
5565
|
for (const e of entries) {
|
|
4358
|
-
if (privateProjects.has(e.project)) continue;
|
|
5566
|
+
if (privateProjects.has(projectRepoName(e.project)) || privateProjects.has(e.project)) continue;
|
|
4359
5567
|
const shape = e.signals?.working_shape ?? null;
|
|
4360
5568
|
if (shape) {
|
|
4361
5569
|
const cur = workingShapes.get(shape) ?? { sessions: 0, agentTimeMs: 0 };
|
|
4362
5570
|
cur.sessions += 1;
|
|
4363
|
-
cur.agentTimeMs += e.numbers.active_min * 6e4;
|
|
5571
|
+
cur.agentTimeMs += Math.round(e.numbers.active_min * 6e4);
|
|
4364
5572
|
workingShapes.set(shape, cur);
|
|
4365
5573
|
}
|
|
4366
5574
|
for (const [name, count] of Object.entries(e.skills)) {
|
|
@@ -4375,6 +5583,12 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4375
5583
|
prs += e.numbers.prs;
|
|
4376
5584
|
commits += e.numbers.commits;
|
|
4377
5585
|
pushes += e.numbers.pushes;
|
|
5586
|
+
if (e.github_repos?.length) {
|
|
5587
|
+
const key = sessionRepo.get(e.session_id) ?? projectRepoName(e.project);
|
|
5588
|
+
const set = projectRepos.get(key) ?? /* @__PURE__ */ new Set();
|
|
5589
|
+
for (const r of e.github_repos) set.add(r);
|
|
5590
|
+
projectRepos.set(key, set);
|
|
5591
|
+
}
|
|
4378
5592
|
if (e.flags.includes("long_autonomous")) {
|
|
4379
5593
|
longCount += 1;
|
|
4380
5594
|
longTotalMin += e.numbers.active_min;
|
|
@@ -4382,11 +5596,21 @@ function buildRichRollupBlocks(day, daySessions, entries, privateProjects) {
|
|
|
4382
5596
|
}
|
|
4383
5597
|
}
|
|
4384
5598
|
return {
|
|
4385
|
-
projects: Array.from(projects.entries()).map(([
|
|
5599
|
+
projects: Array.from(projects.entries()).map(([key, v]) => {
|
|
5600
|
+
const extras = [...projectRepos.get(key) ?? []].filter((r) => r !== v.resolved);
|
|
5601
|
+
const repos = v.resolved ? [v.resolved, ...extras] : extras;
|
|
5602
|
+
return {
|
|
5603
|
+
project: v.project,
|
|
5604
|
+
agentTimeMs: v.agentTimeMs,
|
|
5605
|
+
sessions: v.sessions,
|
|
5606
|
+
...repos.length ? { githubRepos: repos.slice(0, 5) } : {}
|
|
5607
|
+
};
|
|
5608
|
+
}).sort((a, b) => b.agentTimeMs - a.agentTimeMs),
|
|
4386
5609
|
workingShapes: Array.from(workingShapes.entries()).map(([shape, v]) => ({ shape, ...v })).sort((a, b) => b.sessions - a.sessions),
|
|
4387
5610
|
concurrencyPeak: stats.peakConcurrent,
|
|
4388
5611
|
parallelMinutes: Math.round(stats.totalParallelMs / 6e4),
|
|
4389
|
-
|
|
5612
|
+
// Wire schema requires integer minutes (active_min is a float).
|
|
5613
|
+
longAutonomous: { count: longCount, totalMin: Math.round(longTotalMin), maxSingleMin: Math.round(longMaxSingleMin) },
|
|
4390
5614
|
toolErrors,
|
|
4391
5615
|
skillsLoaded: Array.from(skills.entries()).map(([name, sessions]) => ({ name, sessions })).sort((a, b) => b.sessions - a.sessions),
|
|
4392
5616
|
subagentsDispatched: Array.from(subagents.entries()).map(([type, count]) => ({ type, count })).sort((a, b) => b.count - a.count),
|
|
@@ -4415,10 +5639,10 @@ function buildEnrichedExtras(entries) {
|
|
|
4415
5639
|
}
|
|
4416
5640
|
return { outcomeMix, helpfulnessMix, goalMix };
|
|
4417
5641
|
}
|
|
4418
|
-
function buildRichBlocksForDay(day, daySessions, privateProjects, enrichmentOptIn) {
|
|
5642
|
+
function buildRichBlocksForDay(day, daySessions, privateProjects, enrichmentOptIn, resolveRepo) {
|
|
4419
5643
|
const entries = listEntriesForDay(day);
|
|
4420
5644
|
if (entries.length === 0) return void 0;
|
|
4421
|
-
const rich = buildRichRollupBlocks(day, daySessions, entries, privateProjects);
|
|
5645
|
+
const rich = buildRichRollupBlocks(day, daySessions, entries, privateProjects, resolveRepo);
|
|
4422
5646
|
const enriched = enrichmentOptIn ? buildEnrichedExtras(entries) : void 0;
|
|
4423
5647
|
return enriched ? { rich, enriched } : { rich };
|
|
4424
5648
|
}
|
|
@@ -4427,10 +5651,11 @@ function buildIngestPayload(inputs) {
|
|
|
4427
5651
|
return {
|
|
4428
5652
|
ingestId: randomUUID(),
|
|
4429
5653
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4430
|
-
...richRollup || inputs.enrichedExtras ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
5654
|
+
...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
4431
5655
|
...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
|
|
4432
5656
|
...richRollup ? { richRollup } : {},
|
|
4433
5657
|
...inputs.enrichedExtras ? { enrichedExtras: inputs.enrichedExtras } : {},
|
|
5658
|
+
...inputs.artifactSignals ? { artifactSignals: inputs.artifactSignals } : {},
|
|
4434
5659
|
...inputs.usageSnapshot ? { usageSnapshot: inputs.usageSnapshot } : {},
|
|
4435
5660
|
...inputs.planTier ? { planTier: inputs.planTier } : {},
|
|
4436
5661
|
...inputs.cyclePeaks ? { cyclePeaks: inputs.cyclePeaks } : {}
|
|
@@ -4450,19 +5675,81 @@ async function pushToTeamServer(config, payload) {
|
|
|
4450
5675
|
return { ok: res.ok, status: res.status, body };
|
|
4451
5676
|
}
|
|
4452
5677
|
|
|
5678
|
+
// src/team/git-remote.ts
|
|
5679
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, statSync } from "node:fs";
|
|
5680
|
+
import { dirname as dirname3, isAbsolute, join as join5, resolve } from "node:path";
|
|
5681
|
+
var GITHUB_URL_RE = /github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/;
|
|
5682
|
+
function parseGithubRemote(url) {
|
|
5683
|
+
const m = url.trim().match(GITHUB_URL_RE);
|
|
5684
|
+
return m ? `${m[1]}/${m[2]}`.toLowerCase() : null;
|
|
5685
|
+
}
|
|
5686
|
+
function originUrl(configText) {
|
|
5687
|
+
let inOrigin = false;
|
|
5688
|
+
for (const line of configText.split("\n")) {
|
|
5689
|
+
const t = line.trim();
|
|
5690
|
+
if (t.startsWith("[")) {
|
|
5691
|
+
inOrigin = /^\[remote\s+"origin"\]/.test(t);
|
|
5692
|
+
continue;
|
|
5693
|
+
}
|
|
5694
|
+
if (!inOrigin) continue;
|
|
5695
|
+
const m = t.match(/^url\s*=\s*(.+)$/);
|
|
5696
|
+
if (m) return m[1].trim();
|
|
5697
|
+
}
|
|
5698
|
+
return null;
|
|
5699
|
+
}
|
|
5700
|
+
function gitConfigPathFor(dir) {
|
|
5701
|
+
const dotGit = join5(dir, ".git");
|
|
5702
|
+
const st = statSync(dotGit, { throwIfNoEntry: false });
|
|
5703
|
+
if (!st) return null;
|
|
5704
|
+
if (st.isDirectory()) return join5(dotGit, "config");
|
|
5705
|
+
const m = readFileSync6(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
|
|
5706
|
+
if (!m) return null;
|
|
5707
|
+
const gd = isAbsolute(m[1]) ? m[1] : resolve(dir, m[1]);
|
|
5708
|
+
const commondirFile = join5(gd, "commondir");
|
|
5709
|
+
if (existsSync4(commondirFile)) {
|
|
5710
|
+
const common = readFileSync6(commondirFile, "utf8").trim();
|
|
5711
|
+
return join5(isAbsolute(common) ? common : resolve(gd, common), "config");
|
|
5712
|
+
}
|
|
5713
|
+
return join5(gd, "config");
|
|
5714
|
+
}
|
|
5715
|
+
function createRepoResolver() {
|
|
5716
|
+
const cache = /* @__PURE__ */ new Map();
|
|
5717
|
+
return (dir) => {
|
|
5718
|
+
if (!dir || !isAbsolute(dir)) return null;
|
|
5719
|
+
const hit = cache.get(dir);
|
|
5720
|
+
if (hit !== void 0) return hit;
|
|
5721
|
+
let repo = null;
|
|
5722
|
+
try {
|
|
5723
|
+
for (let d = dir; ; d = dirname3(d)) {
|
|
5724
|
+
const config = gitConfigPathFor(d);
|
|
5725
|
+
if (config && existsSync4(config)) {
|
|
5726
|
+
const url = originUrl(readFileSync6(config, "utf8"));
|
|
5727
|
+
repo = url ? parseGithubRemote(url) : null;
|
|
5728
|
+
break;
|
|
5729
|
+
}
|
|
5730
|
+
if (d === dirname3(d)) break;
|
|
5731
|
+
}
|
|
5732
|
+
} catch {
|
|
5733
|
+
repo = null;
|
|
5734
|
+
}
|
|
5735
|
+
cache.set(dir, repo);
|
|
5736
|
+
return repo;
|
|
5737
|
+
};
|
|
5738
|
+
}
|
|
5739
|
+
|
|
4453
5740
|
// src/team/queue.ts
|
|
4454
5741
|
init_fs();
|
|
4455
|
-
import { readFileSync as
|
|
4456
|
-
import { dirname as
|
|
5742
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, appendFileSync as appendFileSync2, statSync as statSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
5743
|
+
import { dirname as dirname4 } from "node:path";
|
|
4457
5744
|
var QUEUE_PATH = cclensPath("ingest-queue.jsonl");
|
|
4458
5745
|
var MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
4459
5746
|
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
4460
5747
|
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
4461
|
-
mkdirSync5(
|
|
5748
|
+
mkdirSync5(dirname4(queuePath), { recursive: true });
|
|
4462
5749
|
const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4463
5750
|
appendFileSync2(queuePath, JSON.stringify(entry) + "\n", "utf8");
|
|
4464
5751
|
try {
|
|
4465
|
-
const { size } =
|
|
5752
|
+
const { size } = statSync2(queuePath);
|
|
4466
5753
|
if (size > MAX_SIZE_BYTES) {
|
|
4467
5754
|
pruneOldest(queuePath);
|
|
4468
5755
|
}
|
|
@@ -4472,7 +5759,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
|
4472
5759
|
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
4473
5760
|
let lines;
|
|
4474
5761
|
try {
|
|
4475
|
-
lines =
|
|
5762
|
+
lines = readFileSync7(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
4476
5763
|
} catch {
|
|
4477
5764
|
return [];
|
|
4478
5765
|
}
|
|
@@ -4493,7 +5780,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
|
4493
5780
|
function pruneOldest(queuePath) {
|
|
4494
5781
|
let lines;
|
|
4495
5782
|
try {
|
|
4496
|
-
lines =
|
|
5783
|
+
lines = readFileSync7(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
4497
5784
|
} catch {
|
|
4498
5785
|
return;
|
|
4499
5786
|
}
|
|
@@ -4506,8 +5793,8 @@ init_storage();
|
|
|
4506
5793
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4507
5794
|
|
|
4508
5795
|
// src/usage/profile.ts
|
|
4509
|
-
import { existsSync as
|
|
4510
|
-
import { dirname as
|
|
5796
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
5797
|
+
import { dirname as dirname5 } from "node:path";
|
|
4511
5798
|
var PROFILE_ENDPOINT = "https://api.anthropic.com/api/oauth/profile";
|
|
4512
5799
|
var BETA_HEADER2 = "oauth-2025-04-20";
|
|
4513
5800
|
var PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -4550,9 +5837,9 @@ async function fetchProfile(nowMs = Date.now()) {
|
|
|
4550
5837
|
};
|
|
4551
5838
|
}
|
|
4552
5839
|
function readCachedProfile(cachePath) {
|
|
4553
|
-
if (!
|
|
5840
|
+
if (!existsSync5(cachePath)) return null;
|
|
4554
5841
|
try {
|
|
4555
|
-
const raw = JSON.parse(
|
|
5842
|
+
const raw = JSON.parse(readFileSync8(cachePath, "utf8"));
|
|
4556
5843
|
if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
|
|
4557
5844
|
return raw;
|
|
4558
5845
|
} catch {
|
|
@@ -4560,7 +5847,7 @@ function readCachedProfile(cachePath) {
|
|
|
4560
5847
|
}
|
|
4561
5848
|
}
|
|
4562
5849
|
function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
|
|
4563
|
-
mkdirSync6(
|
|
5850
|
+
mkdirSync6(dirname5(cachePath), { recursive: true });
|
|
4564
5851
|
writeFileSync5(
|
|
4565
5852
|
cachePath,
|
|
4566
5853
|
JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
|
|
@@ -4722,12 +6009,12 @@ async function runTeamBackfill(log3 = noopLog, filePath = USAGE_LOG, configOverr
|
|
|
4722
6009
|
// src/team/last-push.ts
|
|
4723
6010
|
init_fs();
|
|
4724
6011
|
import { writeFileSync as writeFileSync6, unlinkSync as unlinkSync2, mkdirSync as mkdirSync7 } from "node:fs";
|
|
4725
|
-
import { join as
|
|
6012
|
+
import { join as join6 } from "node:path";
|
|
4726
6013
|
var LAST_PUSH_FILE = "team-last-push.json";
|
|
4727
6014
|
function write(record, dir) {
|
|
4728
6015
|
const d = dir ?? cclensHome();
|
|
4729
6016
|
mkdirSync7(d, { recursive: true });
|
|
4730
|
-
writeFileSync6(
|
|
6017
|
+
writeFileSync6(join6(d, LAST_PUSH_FILE), JSON.stringify(record, null, 2), { mode: 384 });
|
|
4731
6018
|
}
|
|
4732
6019
|
function writeLastPushSuccess(payload, dir) {
|
|
4733
6020
|
write({ pushedAt: (/* @__PURE__ */ new Date()).toISOString(), ok: true, payload }, dir);
|
|
@@ -4753,6 +6040,7 @@ async function dispatchCommand(command, config, log3) {
|
|
|
4753
6040
|
async function runActivityBackfill(command, config, log3) {
|
|
4754
6041
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4755
6042
|
const { toLocalDay: toLocalDay3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
6043
|
+
const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
|
|
4756
6044
|
const days = command.params.days;
|
|
4757
6045
|
const todayMs = Date.now();
|
|
4758
6046
|
const targetDayMs = todayMs - (days - 1) * 24 * 60 * 60 * 1e3;
|
|
@@ -4778,9 +6066,24 @@ async function runActivityBackfill(command, config, log3) {
|
|
|
4778
6066
|
summary: { pushed: 0, fromDay: targetDay }
|
|
4779
6067
|
};
|
|
4780
6068
|
}
|
|
6069
|
+
const privateProjects = new Set(config.privateProjects ?? []);
|
|
6070
|
+
const enrichmentOptIn = !!config.enrichmentOptIn;
|
|
6071
|
+
const resolveRepo = createRepoResolver();
|
|
4781
6072
|
let pushed = 0;
|
|
4782
6073
|
for (const rollup of rollups) {
|
|
4783
|
-
const
|
|
6074
|
+
const daySessions = sessions.filter((s) => sessionTouchesDay(s, rollup.day));
|
|
6075
|
+
const richBlocks = buildRichBlocksForDay(rollup.day, daySessions, privateProjects, enrichmentOptIn, resolveRepo);
|
|
6076
|
+
let artifactSignals = null;
|
|
6077
|
+
try {
|
|
6078
|
+
artifactSignals = probeArtifactSignals2({ day: rollup.day, extraRoots: [process.cwd()] });
|
|
6079
|
+
} catch {
|
|
6080
|
+
}
|
|
6081
|
+
const payload = buildIngestPayload({
|
|
6082
|
+
rollup,
|
|
6083
|
+
richExtras: richBlocks?.rich,
|
|
6084
|
+
enrichedExtras: richBlocks?.enriched,
|
|
6085
|
+
artifactSignals: artifactSignals ?? void 0
|
|
6086
|
+
});
|
|
4784
6087
|
const result = await pushToTeamServer(config, payload);
|
|
4785
6088
|
if (!result.ok) {
|
|
4786
6089
|
return {
|
|
@@ -4906,6 +6209,8 @@ async function runTeamSync(log3 = noopLog2, configOverride, options = {}) {
|
|
|
4906
6209
|
let lastPushedDay;
|
|
4907
6210
|
const privateProjects = new Set(config.privateProjects ?? []);
|
|
4908
6211
|
const enrichmentOptIn = !!config.enrichmentOptIn;
|
|
6212
|
+
const resolveRepo = createRepoResolver();
|
|
6213
|
+
const { probeArtifactSignals: probeArtifactSignals2 } = await Promise.resolve().then(() => (init_file_probe(), file_probe_exports));
|
|
4909
6214
|
for (let i = 0; i < rollups.length; i++) {
|
|
4910
6215
|
const rollup = rollups[i];
|
|
4911
6216
|
const isLatest = i === rollups.length - 1;
|
|
@@ -4914,12 +6219,22 @@ async function runTeamSync(log3 = noopLog2, configOverride, options = {}) {
|
|
|
4914
6219
|
rollup.day,
|
|
4915
6220
|
daySessions,
|
|
4916
6221
|
privateProjects,
|
|
4917
|
-
enrichmentOptIn
|
|
6222
|
+
enrichmentOptIn,
|
|
6223
|
+
resolveRepo
|
|
4918
6224
|
);
|
|
6225
|
+
let artifactSignals = null;
|
|
6226
|
+
try {
|
|
6227
|
+
artifactSignals = probeArtifactSignals2({
|
|
6228
|
+
day: rollup.day,
|
|
6229
|
+
extraRoots: [process.cwd()]
|
|
6230
|
+
});
|
|
6231
|
+
} catch {
|
|
6232
|
+
}
|
|
4919
6233
|
const payload = buildIngestPayload({
|
|
4920
6234
|
rollup,
|
|
4921
6235
|
richExtras: richBlocks?.rich,
|
|
4922
6236
|
enrichedExtras: richBlocks?.enriched,
|
|
6237
|
+
artifactSignals: artifactSignals ?? void 0,
|
|
4923
6238
|
usageSnapshot: isLatest ? usageSnapshot : void 0,
|
|
4924
6239
|
planTier,
|
|
4925
6240
|
// Same rationale as usageSnapshot — current cycle data only on the
|
|
@@ -5038,8 +6353,8 @@ async function buildCyclePeaksForPush(planTier, loadCurve) {
|
|
|
5038
6353
|
// src/perception/worker.ts
|
|
5039
6354
|
init_dist();
|
|
5040
6355
|
init_fs();
|
|
5041
|
-
import { statSync as
|
|
5042
|
-
import { basename, dirname as
|
|
6356
|
+
import { statSync as statSync4, readFileSync as readFileSync10 } from "node:fs";
|
|
6357
|
+
import { basename, dirname as dirname8 } from "node:path";
|
|
5043
6358
|
|
|
5044
6359
|
// ../entries/dist/signals.js
|
|
5045
6360
|
init_dist();
|
|
@@ -5271,7 +6586,7 @@ function viewEvent(ev) {
|
|
|
5271
6586
|
cwd: rawCwd
|
|
5272
6587
|
};
|
|
5273
6588
|
}
|
|
5274
|
-
var
|
|
6589
|
+
var IDLE_GAP_MS4 = 3 * 60 * 1e3;
|
|
5275
6590
|
var INTERRUPT_RE2 = /\[request interrupted|interrupted by user/i;
|
|
5276
6591
|
var PR_TITLE_RE = /--title\s+["']([^"']+)["']/;
|
|
5277
6592
|
var BASH_CHAIN_SPLIT_RE = /\|\||&&|;|\|/;
|
|
@@ -5383,7 +6698,7 @@ function closeTurn(t, closed, cwd) {
|
|
|
5383
6698
|
let active = 0;
|
|
5384
6699
|
for (let i = 1; i < ts.length; i++) {
|
|
5385
6700
|
const dt = ts[i] - ts[i - 1];
|
|
5386
|
-
if (dt <
|
|
6701
|
+
if (dt < IDLE_GAP_MS4)
|
|
5387
6702
|
active += dt;
|
|
5388
6703
|
}
|
|
5389
6704
|
closed.push({
|
|
@@ -5410,6 +6725,9 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5410
6725
|
const prTitles = [];
|
|
5411
6726
|
let commits = 0;
|
|
5412
6727
|
let pushes = 0;
|
|
6728
|
+
const gitToolUseIds = /* @__PURE__ */ new Set();
|
|
6729
|
+
const githubRepos = /* @__PURE__ */ new Set();
|
|
6730
|
+
const editedDirCounts = /* @__PURE__ */ new Map();
|
|
5413
6731
|
const modelTurns = /* @__PURE__ */ new Map();
|
|
5414
6732
|
let totalToolErrors = 0;
|
|
5415
6733
|
let totalInterrupts = 0;
|
|
@@ -5451,11 +6769,23 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5451
6769
|
} else {
|
|
5452
6770
|
if (Array.isArray(content)) {
|
|
5453
6771
|
for (const c of content) {
|
|
5454
|
-
if (c
|
|
6772
|
+
if (!c || typeof c !== "object" || c.type !== "tool_result")
|
|
6773
|
+
continue;
|
|
6774
|
+
if (c.is_error) {
|
|
5455
6775
|
totalToolErrors++;
|
|
5456
6776
|
if (cur)
|
|
5457
6777
|
cur.toolErrors++;
|
|
5458
6778
|
}
|
|
6779
|
+
const tuId = c.tool_use_id;
|
|
6780
|
+
if (tuId && gitToolUseIds.has(tuId)) {
|
|
6781
|
+
const rc = c.content;
|
|
6782
|
+
const text = typeof rc === "string" ? rc : Array.isArray(rc) ? rc.map((b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : "").join("\n") : "";
|
|
6783
|
+
for (const m of text.matchAll(/(?<![.\w])github\.com[:/]([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git\b|[/\s"'),]|$)/g)) {
|
|
6784
|
+
if (m[1].toLowerCase() === "user-attachments")
|
|
6785
|
+
continue;
|
|
6786
|
+
githubRepos.add(`${m[1]}/${m[2]}`.toLowerCase());
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
5459
6789
|
}
|
|
5460
6790
|
}
|
|
5461
6791
|
if (cur && tsMs !== void 0) {
|
|
@@ -5511,10 +6841,6 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5511
6841
|
if (name === "Skill") {
|
|
5512
6842
|
const sk = String(ct.input?.skill ?? "unknown");
|
|
5513
6843
|
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
6844
|
}
|
|
5519
6845
|
if (name === "Agent") {
|
|
5520
6846
|
const inp = ct.input ?? {};
|
|
@@ -5544,10 +6870,20 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5544
6870
|
commits++;
|
|
5545
6871
|
if (/\bgit\s+push\b/.test(cmd))
|
|
5546
6872
|
pushes++;
|
|
6873
|
+
if (ct.id && /\bgit\s+push\b|\bgh\s+pr\s+/.test(cmd))
|
|
6874
|
+
gitToolUseIds.add(ct.id);
|
|
5547
6875
|
}
|
|
5548
6876
|
if (eventCwd && (name === "Bash" || name === "Edit" || name === "Write" || name === "Read")) {
|
|
5549
6877
|
cwdCounts.set(eventCwd, (cwdCounts.get(eventCwd) ?? 0) + 1);
|
|
5550
6878
|
}
|
|
6879
|
+
if (name === "Edit" || name === "Write" || name === "MultiEdit" || name === "NotebookEdit") {
|
|
6880
|
+
const fp = String(ct.input?.file_path ?? ct.input?.notebook_path ?? "");
|
|
6881
|
+
const slash = fp.lastIndexOf("/");
|
|
6882
|
+
if (slash > 0) {
|
|
6883
|
+
const dir = fp.slice(0, slash);
|
|
6884
|
+
editedDirCounts.set(dir, (editedDirCounts.get(dir) ?? 0) + 1);
|
|
6885
|
+
}
|
|
6886
|
+
}
|
|
5551
6887
|
}
|
|
5552
6888
|
}
|
|
5553
6889
|
}
|
|
@@ -5559,7 +6895,7 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5559
6895
|
let activeMs2 = 0;
|
|
5560
6896
|
for (let i = 1; i < tsSorted.length; i++) {
|
|
5561
6897
|
const dt = tsSorted[i] - tsSorted[i - 1];
|
|
5562
|
-
if (dt <
|
|
6898
|
+
if (dt < IDLE_GAP_MS4)
|
|
5563
6899
|
activeMs2 += dt;
|
|
5564
6900
|
}
|
|
5565
6901
|
const tsSortedStrings = dayEvents.map((e) => e.timestamp).filter((t) => !!t).sort();
|
|
@@ -5572,6 +6908,8 @@ function aggregateDay(dayEvents, _sessionFallbackProject) {
|
|
|
5572
6908
|
prTitles,
|
|
5573
6909
|
commits,
|
|
5574
6910
|
pushes,
|
|
6911
|
+
githubRepos: [...githubRepos].slice(0, 5),
|
|
6912
|
+
editedDirs: [...editedDirCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([dir]) => dir),
|
|
5575
6913
|
modelTurns,
|
|
5576
6914
|
totalToolErrors,
|
|
5577
6915
|
totalInterrupts,
|
|
@@ -5725,6 +7063,8 @@ function buildEntries(sessionDetail) {
|
|
|
5725
7063
|
first_user,
|
|
5726
7064
|
final_agent,
|
|
5727
7065
|
pr_titles: agg.prTitles,
|
|
7066
|
+
...agg.githubRepos.length ? { github_repos: agg.githubRepos } : {},
|
|
7067
|
+
...agg.editedDirs.length ? { edited_dirs: agg.editedDirs } : {},
|
|
5728
7068
|
top_tools,
|
|
5729
7069
|
skills,
|
|
5730
7070
|
subagents,
|
|
@@ -5744,8 +7084,8 @@ function buildEntries(sessionDetail) {
|
|
|
5744
7084
|
|
|
5745
7085
|
// src/perception/state.ts
|
|
5746
7086
|
init_fs();
|
|
5747
|
-
import { existsSync as
|
|
5748
|
-
import { dirname as
|
|
7087
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, renameSync as renameSync3 } from "node:fs";
|
|
7088
|
+
import { dirname as dirname7 } from "node:path";
|
|
5749
7089
|
var STALE_MS = 15 * 60 * 1e3;
|
|
5750
7090
|
var pathCached = null;
|
|
5751
7091
|
function statePath() {
|
|
@@ -5755,7 +7095,7 @@ function statePath() {
|
|
|
5755
7095
|
}
|
|
5756
7096
|
function readState() {
|
|
5757
7097
|
const p = statePath();
|
|
5758
|
-
if (!
|
|
7098
|
+
if (!existsSync7(p)) {
|
|
5759
7099
|
return {
|
|
5760
7100
|
sweep_in_progress: false,
|
|
5761
7101
|
last_sweep_started_at: null,
|
|
@@ -5763,12 +7103,12 @@ function readState() {
|
|
|
5763
7103
|
file_checkpoints: {}
|
|
5764
7104
|
};
|
|
5765
7105
|
}
|
|
5766
|
-
const raw =
|
|
7106
|
+
const raw = readFileSync9(p, "utf8");
|
|
5767
7107
|
return JSON.parse(raw);
|
|
5768
7108
|
}
|
|
5769
7109
|
function writeState(s) {
|
|
5770
7110
|
const p = statePath();
|
|
5771
|
-
mkdirSync8(
|
|
7111
|
+
mkdirSync8(dirname7(p), { recursive: true });
|
|
5772
7112
|
const tmp = `${p}.tmp`;
|
|
5773
7113
|
writeFileSync7(tmp, JSON.stringify(s, null, 2), "utf8");
|
|
5774
7114
|
renameSync3(tmp, p);
|
|
@@ -5799,18 +7139,18 @@ function updateCheckpoint(jsonlPath, cp) {
|
|
|
5799
7139
|
}
|
|
5800
7140
|
|
|
5801
7141
|
// src/perception/scan.ts
|
|
5802
|
-
import { readdirSync as
|
|
5803
|
-
import { join as
|
|
5804
|
-
import { homedir as
|
|
7142
|
+
import { readdirSync as readdirSync4 } from "node:fs";
|
|
7143
|
+
import { join as join8 } from "node:path";
|
|
7144
|
+
import { homedir as homedir3 } from "node:os";
|
|
5805
7145
|
async function listAllSessionJsonls(root) {
|
|
5806
|
-
const projectsRoot = root ??
|
|
7146
|
+
const projectsRoot = root ?? join8(homedir3(), ".claude", "projects");
|
|
5807
7147
|
const out = [];
|
|
5808
7148
|
try {
|
|
5809
|
-
for (const project of
|
|
5810
|
-
const dir =
|
|
7149
|
+
for (const project of readdirSync4(projectsRoot)) {
|
|
7150
|
+
const dir = join8(projectsRoot, project);
|
|
5811
7151
|
try {
|
|
5812
|
-
for (const f of
|
|
5813
|
-
if (f.endsWith(".jsonl")) out.push(
|
|
7152
|
+
for (const f of readdirSync4(dir)) {
|
|
7153
|
+
if (f.endsWith(".jsonl")) out.push(join8(dir, f));
|
|
5814
7154
|
}
|
|
5815
7155
|
} catch {
|
|
5816
7156
|
}
|
|
@@ -5843,10 +7183,10 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5843
7183
|
const files = await listAllSessionJsonls(opts.projectsRoot);
|
|
5844
7184
|
for (const f of files) {
|
|
5845
7185
|
try {
|
|
5846
|
-
const stat =
|
|
7186
|
+
const stat = statSync4(f);
|
|
5847
7187
|
const prev = state.file_checkpoints[f];
|
|
5848
7188
|
if (prev && prev.byte_offset >= stat.size) continue;
|
|
5849
|
-
const raw =
|
|
7189
|
+
const raw = readFileSync10(f, "utf8");
|
|
5850
7190
|
const rawLines = raw.split("\n").filter(Boolean).map((l) => {
|
|
5851
7191
|
try {
|
|
5852
7192
|
return JSON.parse(l);
|
|
@@ -5857,7 +7197,7 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5857
7197
|
if (rawLines.length === 0) continue;
|
|
5858
7198
|
const { meta, events } = parseTranscript(rawLines);
|
|
5859
7199
|
const fileName = basename(f);
|
|
5860
|
-
const projectDir = basename(
|
|
7200
|
+
const projectDir = basename(dirname8(f));
|
|
5861
7201
|
const sessionId = fileName.replace(/\.jsonl$/, "");
|
|
5862
7202
|
const sd = {
|
|
5863
7203
|
...meta,
|
|
@@ -5896,7 +7236,7 @@ async function runPerceptionSweep(opts = {}) {
|
|
|
5896
7236
|
const built = buildEntries(detail);
|
|
5897
7237
|
for (const e of built) {
|
|
5898
7238
|
try {
|
|
5899
|
-
const stat =
|
|
7239
|
+
const stat = statSync4(meta.filePath);
|
|
5900
7240
|
e.source_checkpoint.byte_offset = stat.size;
|
|
5901
7241
|
} catch {
|
|
5902
7242
|
}
|
|
@@ -6398,8 +7738,8 @@ function getErrorMap() {
|
|
|
6398
7738
|
|
|
6399
7739
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
6400
7740
|
var makeIssue = (params) => {
|
|
6401
|
-
const { data, path:
|
|
6402
|
-
const fullPath = [...
|
|
7741
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
7742
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
6403
7743
|
const fullIssue = {
|
|
6404
7744
|
...issueData,
|
|
6405
7745
|
path: fullPath
|
|
@@ -6515,11 +7855,11 @@ var errorUtil;
|
|
|
6515
7855
|
|
|
6516
7856
|
// ../../node_modules/zod/v3/types.js
|
|
6517
7857
|
var ParseInputLazyPath = class {
|
|
6518
|
-
constructor(parent, value,
|
|
7858
|
+
constructor(parent, value, path7, key) {
|
|
6519
7859
|
this._cachedPath = [];
|
|
6520
7860
|
this.parent = parent;
|
|
6521
7861
|
this.data = value;
|
|
6522
|
-
this._path =
|
|
7862
|
+
this._path = path7;
|
|
6523
7863
|
this._key = key;
|
|
6524
7864
|
}
|
|
6525
7865
|
get path() {
|
|
@@ -10053,14 +11393,14 @@ var ENRICHMENT_SYSTEM_PROMPT = SYSTEM_PROMPT;
|
|
|
10053
11393
|
// ../entries/dist/llm-runner.js
|
|
10054
11394
|
init_fs();
|
|
10055
11395
|
import { spawn } from "node:child_process";
|
|
10056
|
-
import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as
|
|
10057
|
-
import { join as
|
|
11396
|
+
import { mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, writeFileSync as writeFileSync9, existsSync as existsSync9 } from "node:fs";
|
|
11397
|
+
import { join as join10 } from "node:path";
|
|
10058
11398
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
10059
11399
|
|
|
10060
11400
|
// ../entries/dist/tmux-runner.js
|
|
10061
|
-
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, existsSync as
|
|
10062
|
-
import { join as
|
|
10063
|
-
import { homedir as
|
|
11401
|
+
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";
|
|
11402
|
+
import { join as join9 } from "node:path";
|
|
11403
|
+
import { homedir as homedir4 } from "node:os";
|
|
10064
11404
|
import { spawnSync } from "node:child_process";
|
|
10065
11405
|
var TmuxUnavailableError = class extends Error {
|
|
10066
11406
|
constructor(message) {
|
|
@@ -10088,16 +11428,16 @@ function tmuxRunnerAvailable() {
|
|
|
10088
11428
|
return { ok: true };
|
|
10089
11429
|
}
|
|
10090
11430
|
function runtimeCwd() {
|
|
10091
|
-
const dir =
|
|
10092
|
-
if (!
|
|
11431
|
+
const dir = join9(homedir4(), ".cclens", "runtime");
|
|
11432
|
+
if (!existsSync8(dir))
|
|
10093
11433
|
mkdirSync9(dir, { recursive: true });
|
|
10094
11434
|
return realpathSync(dir);
|
|
10095
11435
|
}
|
|
10096
11436
|
function ensureRuntimeCwdTrusted(cwd) {
|
|
10097
|
-
const cfgPath =
|
|
11437
|
+
const cfgPath = join9(homedir4(), ".claude.json");
|
|
10098
11438
|
let cfg;
|
|
10099
11439
|
try {
|
|
10100
|
-
cfg = JSON.parse(
|
|
11440
|
+
cfg = JSON.parse(readFileSync11(cfgPath, "utf8"));
|
|
10101
11441
|
} catch {
|
|
10102
11442
|
return;
|
|
10103
11443
|
}
|
|
@@ -10140,9 +11480,9 @@ async function runClaudeUnderTmuxImpl(args) {
|
|
|
10140
11480
|
ensureRuntimeCwdTrusted(cwd);
|
|
10141
11481
|
const runId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
10142
11482
|
const sessionName = `cclens-${runId}`;
|
|
10143
|
-
const systemFile =
|
|
10144
|
-
const userFile =
|
|
10145
|
-
const wrapper =
|
|
11483
|
+
const systemFile = join9(cwd, `system-${runId}.txt`);
|
|
11484
|
+
const userFile = join9(cwd, `user-${runId}.txt`);
|
|
11485
|
+
const wrapper = join9(cwd, `run-${runId}.sh`);
|
|
10146
11486
|
writeFileSync8(systemFile, args.systemPrompt);
|
|
10147
11487
|
writeFileSync8(userFile, args.reminder ? `${args.userPrompt}
|
|
10148
11488
|
|
|
@@ -10221,35 +11561,35 @@ function num(v) {
|
|
|
10221
11561
|
function sleep(ms) {
|
|
10222
11562
|
return new Promise((r) => setTimeout(r, ms));
|
|
10223
11563
|
}
|
|
10224
|
-
var PROJECTS_ROOT = () =>
|
|
11564
|
+
var PROJECTS_ROOT = () => join9(homedir4(), ".claude", "projects");
|
|
10225
11565
|
function snapshotAllTranscripts() {
|
|
10226
11566
|
const out = /* @__PURE__ */ new Set();
|
|
10227
11567
|
const root = PROJECTS_ROOT();
|
|
10228
11568
|
let subs;
|
|
10229
11569
|
try {
|
|
10230
|
-
subs =
|
|
11570
|
+
subs = readdirSync5(root);
|
|
10231
11571
|
} catch {
|
|
10232
11572
|
return out;
|
|
10233
11573
|
}
|
|
10234
11574
|
for (const sub of subs) {
|
|
10235
|
-
const dir =
|
|
11575
|
+
const dir = join9(root, sub);
|
|
10236
11576
|
let files;
|
|
10237
11577
|
try {
|
|
10238
|
-
files =
|
|
11578
|
+
files = readdirSync5(dir);
|
|
10239
11579
|
} catch {
|
|
10240
11580
|
continue;
|
|
10241
11581
|
}
|
|
10242
11582
|
for (const f of files) {
|
|
10243
11583
|
if (f.endsWith(".jsonl"))
|
|
10244
|
-
out.add(
|
|
11584
|
+
out.add(join9(dir, f));
|
|
10245
11585
|
}
|
|
10246
11586
|
}
|
|
10247
11587
|
return out;
|
|
10248
11588
|
}
|
|
10249
|
-
function readJsonlCwd(
|
|
11589
|
+
function readJsonlCwd(path7, maxLines = 8) {
|
|
10250
11590
|
let raw;
|
|
10251
11591
|
try {
|
|
10252
|
-
raw =
|
|
11592
|
+
raw = readFileSync11(path7, "utf8");
|
|
10253
11593
|
} catch {
|
|
10254
11594
|
return void 0;
|
|
10255
11595
|
}
|
|
@@ -10277,22 +11617,22 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
10277
11617
|
const root = PROJECTS_ROOT();
|
|
10278
11618
|
let subs;
|
|
10279
11619
|
try {
|
|
10280
|
-
subs =
|
|
11620
|
+
subs = readdirSync5(root);
|
|
10281
11621
|
} catch {
|
|
10282
11622
|
subs = [];
|
|
10283
11623
|
}
|
|
10284
11624
|
for (const sub of subs) {
|
|
10285
|
-
const dir =
|
|
11625
|
+
const dir = join9(root, sub);
|
|
10286
11626
|
let files;
|
|
10287
11627
|
try {
|
|
10288
|
-
files =
|
|
11628
|
+
files = readdirSync5(dir);
|
|
10289
11629
|
} catch {
|
|
10290
11630
|
continue;
|
|
10291
11631
|
}
|
|
10292
11632
|
for (const f of files) {
|
|
10293
11633
|
if (!f.endsWith(".jsonl"))
|
|
10294
11634
|
continue;
|
|
10295
|
-
const full =
|
|
11635
|
+
const full = join9(dir, f);
|
|
10296
11636
|
if (existingBefore.has(full))
|
|
10297
11637
|
continue;
|
|
10298
11638
|
if (readJsonlCwd(full) === targetCwd)
|
|
@@ -10303,10 +11643,10 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
10303
11643
|
}
|
|
10304
11644
|
throw new TmuxRunError(`timeout waiting for claude to create the session transcript (cwd: ${targetCwd})`);
|
|
10305
11645
|
}
|
|
10306
|
-
function parseTranscript2(
|
|
11646
|
+
function parseTranscript2(path7, defaultModel) {
|
|
10307
11647
|
let raw;
|
|
10308
11648
|
try {
|
|
10309
|
-
raw =
|
|
11649
|
+
raw = readFileSync11(path7, "utf8");
|
|
10310
11650
|
} catch {
|
|
10311
11651
|
return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
|
|
10312
11652
|
}
|
|
@@ -10366,7 +11706,7 @@ function cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath) {
|
|
|
10366
11706
|
}
|
|
10367
11707
|
for (const f of [`system-${runId}.txt`, `user-${runId}.txt`, `run-${runId}.sh`]) {
|
|
10368
11708
|
try {
|
|
10369
|
-
unlinkSync3(
|
|
11709
|
+
unlinkSync3(join9(cwd, f));
|
|
10370
11710
|
} catch {
|
|
10371
11711
|
}
|
|
10372
11712
|
}
|
|
@@ -10381,7 +11721,7 @@ function shellEscape(s) {
|
|
|
10381
11721
|
// ../entries/dist/llm-runner.js
|
|
10382
11722
|
var RUNS_DIR = cclensPath("llm-runs");
|
|
10383
11723
|
function ensureRunsDir() {
|
|
10384
|
-
if (!
|
|
11724
|
+
if (!existsSync9(RUNS_DIR)) {
|
|
10385
11725
|
try {
|
|
10386
11726
|
mkdirSync10(RUNS_DIR, { recursive: true });
|
|
10387
11727
|
} catch {
|
|
@@ -10410,17 +11750,17 @@ function newRunId(kind) {
|
|
|
10410
11750
|
return `${ts}_${kind}_${short}`;
|
|
10411
11751
|
}
|
|
10412
11752
|
function tracePath(runId) {
|
|
10413
|
-
return
|
|
11753
|
+
return join10(RUNS_DIR, `${runId}.jsonl`);
|
|
10414
11754
|
}
|
|
10415
|
-
function safeAppend(
|
|
11755
|
+
function safeAppend(path7, line) {
|
|
10416
11756
|
try {
|
|
10417
|
-
appendFileSync3(
|
|
11757
|
+
appendFileSync3(path7, line);
|
|
10418
11758
|
} catch {
|
|
10419
11759
|
}
|
|
10420
11760
|
}
|
|
10421
|
-
function safeWrite(
|
|
11761
|
+
function safeWrite(path7, line) {
|
|
10422
11762
|
try {
|
|
10423
|
-
writeFileSync9(
|
|
11763
|
+
writeFileSync9(path7, line);
|
|
10424
11764
|
} catch {
|
|
10425
11765
|
}
|
|
10426
11766
|
}
|
|
@@ -10498,7 +11838,7 @@ async function runClaudeSubprocess(args) {
|
|
|
10498
11838
|
return runClaudePrintMode(args);
|
|
10499
11839
|
}
|
|
10500
11840
|
function runClaudePrintMode(args) {
|
|
10501
|
-
return new Promise((
|
|
11841
|
+
return new Promise((resolve3, reject) => {
|
|
10502
11842
|
ensureRunsDir();
|
|
10503
11843
|
const kind = detectKindFromSystemPrompt(args.systemPrompt);
|
|
10504
11844
|
const runId = newRunId(kind);
|
|
@@ -10629,7 +11969,7 @@ ${args.reminder}` : args.userPrompt;
|
|
|
10629
11969
|
reject(new Error(`claude exited ${code}: ${stderr.trim().slice(0, 300)}`));
|
|
10630
11970
|
return;
|
|
10631
11971
|
}
|
|
10632
|
-
|
|
11972
|
+
resolve3({ content: buffer, input_tokens: inputTokens, output_tokens: outputTokens, model: modelUsed });
|
|
10633
11973
|
});
|
|
10634
11974
|
proc.on("error", (err) => {
|
|
10635
11975
|
safeAppend(trace, JSON.stringify({ _meta: { type: "spawn_error", run_id: runId, ts: (/* @__PURE__ */ new Date()).toISOString(), error: err.message } }) + "\n");
|
|
@@ -10809,8 +12149,8 @@ function applyEnrichmentError(entry, errorMessage, model, costUsd, generatedAt,
|
|
|
10809
12149
|
|
|
10810
12150
|
// ../entries/dist/budget.js
|
|
10811
12151
|
init_fs();
|
|
10812
|
-
import { appendFileSync as appendFileSync4, readFileSync as
|
|
10813
|
-
import { dirname as
|
|
12152
|
+
import { appendFileSync as appendFileSync4, readFileSync as readFileSync12, existsSync as existsSync10, mkdirSync as mkdirSync11 } from "node:fs";
|
|
12153
|
+
import { dirname as dirname9 } from "node:path";
|
|
10814
12154
|
var spendPathCached = null;
|
|
10815
12155
|
function spendPath() {
|
|
10816
12156
|
if (spendPathCached)
|
|
@@ -10820,17 +12160,17 @@ function spendPath() {
|
|
|
10820
12160
|
}
|
|
10821
12161
|
function appendSpend(record) {
|
|
10822
12162
|
const p = spendPath();
|
|
10823
|
-
mkdirSync11(
|
|
12163
|
+
mkdirSync11(dirname9(p), { recursive: true });
|
|
10824
12164
|
appendFileSync4(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
|
|
10825
12165
|
}
|
|
10826
12166
|
function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
10827
12167
|
const p = spendPath();
|
|
10828
|
-
if (!
|
|
12168
|
+
if (!existsSync10(p))
|
|
10829
12169
|
return 0;
|
|
10830
12170
|
const year = now.getUTCFullYear();
|
|
10831
12171
|
const month = now.getUTCMonth();
|
|
10832
12172
|
let total = 0;
|
|
10833
|
-
const raw =
|
|
12173
|
+
const raw = readFileSync12(p, "utf8");
|
|
10834
12174
|
for (const line of raw.split("\n")) {
|
|
10835
12175
|
if (!line)
|
|
10836
12176
|
continue;
|
|
@@ -10852,7 +12192,7 @@ function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
|
10852
12192
|
|
|
10853
12193
|
// ../entries/dist/pipeline-lock.js
|
|
10854
12194
|
init_fs();
|
|
10855
|
-
import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as
|
|
12195
|
+
import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync11, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
|
|
10856
12196
|
var STALE_MS2 = 60 * 1e3;
|
|
10857
12197
|
var HEARTBEAT_MS = 30 * 1e3;
|
|
10858
12198
|
var lockPathCached = null;
|
|
@@ -10898,13 +12238,13 @@ function pidAlive(pid) {
|
|
|
10898
12238
|
}
|
|
10899
12239
|
function interactiveLockFresh(nowMs) {
|
|
10900
12240
|
const p = lockPath();
|
|
10901
|
-
if (!
|
|
12241
|
+
if (!existsSync11(p))
|
|
10902
12242
|
return false;
|
|
10903
12243
|
try {
|
|
10904
|
-
const mtime =
|
|
12244
|
+
const mtime = statSync5(p).mtimeMs;
|
|
10905
12245
|
if (nowMs - mtime > STALE_MS2)
|
|
10906
12246
|
return false;
|
|
10907
|
-
const pid = Number(
|
|
12247
|
+
const pid = Number(readFileSync13(p, "utf8").trim());
|
|
10908
12248
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
10909
12249
|
return false;
|
|
10910
12250
|
if (!pidAlive(pid))
|
|
@@ -10919,7 +12259,7 @@ function interactiveLockFresh(nowMs) {
|
|
|
10919
12259
|
var THIRTY_MIN_MS = 30 * 60 * 1e3;
|
|
10920
12260
|
|
|
10921
12261
|
// ../entries/dist/settings.js
|
|
10922
|
-
import { readFileSync as
|
|
12262
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync12, existsSync as existsSync12 } from "node:fs";
|
|
10923
12263
|
init_fs();
|
|
10924
12264
|
var DEFAULT_SETTINGS = {
|
|
10925
12265
|
ai_features: {
|
|
@@ -10951,10 +12291,10 @@ function fromDisk(d) {
|
|
|
10951
12291
|
}
|
|
10952
12292
|
function readSettings() {
|
|
10953
12293
|
const p = settingsPath();
|
|
10954
|
-
if (!
|
|
12294
|
+
if (!existsSync12(p))
|
|
10955
12295
|
return DEFAULT_SETTINGS;
|
|
10956
12296
|
try {
|
|
10957
|
-
const raw =
|
|
12297
|
+
const raw = readFileSync14(p, "utf8");
|
|
10958
12298
|
return fromDisk(JSON.parse(raw));
|
|
10959
12299
|
} catch {
|
|
10960
12300
|
return DEFAULT_SETTINGS;
|
|
@@ -11127,7 +12467,7 @@ function rollupOutcomeDay(entries) {
|
|
|
11127
12467
|
return "exploratory";
|
|
11128
12468
|
return "trivial";
|
|
11129
12469
|
}
|
|
11130
|
-
function
|
|
12470
|
+
function truncate5(s, max) {
|
|
11131
12471
|
if (s.length <= max)
|
|
11132
12472
|
return s;
|
|
11133
12473
|
return s.slice(0, max - 1).trimEnd() + "\u2026";
|
|
@@ -11183,7 +12523,7 @@ function computeDaySignals(entries) {
|
|
|
11183
12523
|
type,
|
|
11184
12524
|
count: v.count,
|
|
11185
12525
|
sample_description: v.sample_description,
|
|
11186
|
-
sample_prompt_preview:
|
|
12526
|
+
sample_prompt_preview: truncate5(v.sample_prompt_preview, 200)
|
|
11187
12527
|
}));
|
|
11188
12528
|
const frameCounts = /* @__PURE__ */ new Map();
|
|
11189
12529
|
for (const s of signalsList) {
|
|
@@ -11202,7 +12542,7 @@ function computeDaySignals(entries) {
|
|
|
11202
12542
|
if ((e.first_user ?? "").length > 0)
|
|
11203
12543
|
verbosity_distribution[s.verbosity] += 1;
|
|
11204
12544
|
for (const ref of s.external_refs) {
|
|
11205
|
-
external_refs.push({ session_id: e.session_id, kind: ref.kind, preview:
|
|
12545
|
+
external_refs.push({ session_id: e.session_id, kind: ref.kind, preview: truncate5(ref.preview, 200) });
|
|
11206
12546
|
}
|
|
11207
12547
|
const ints = e.numbers.interrupts ?? 0;
|
|
11208
12548
|
interrupts += ints;
|
|
@@ -12045,7 +13385,7 @@ function computeInteractionModes(entries) {
|
|
|
12045
13385
|
date: entry.local_day,
|
|
12046
13386
|
project_display: prettyProject3(entry.project),
|
|
12047
13387
|
type: sa.type,
|
|
12048
|
-
prompt_preview:
|
|
13388
|
+
prompt_preview: truncate6(sa.prompt_preview, 200)
|
|
12049
13389
|
});
|
|
12050
13390
|
}
|
|
12051
13391
|
const skillExamples = [];
|
|
@@ -12062,7 +13402,7 @@ function computeInteractionModes(entries) {
|
|
|
12062
13402
|
skillExamples.push({
|
|
12063
13403
|
date: e.local_day,
|
|
12064
13404
|
skill,
|
|
12065
|
-
first_user_preview:
|
|
13405
|
+
first_user_preview: truncate6(e.first_user, 200)
|
|
12066
13406
|
});
|
|
12067
13407
|
}
|
|
12068
13408
|
}
|
|
@@ -12079,7 +13419,7 @@ function computeInteractionModes(entries) {
|
|
|
12079
13419
|
project_display: prettyProject3(longestTurnEntry.project),
|
|
12080
13420
|
active_min: longestTurnEntry.numbers.active_min,
|
|
12081
13421
|
top_tools: longestTurnEntry.top_tools.slice(0, 5),
|
|
12082
|
-
first_user_preview:
|
|
13422
|
+
first_user_preview: truncate6(longestTurnEntry.first_user, 200)
|
|
12083
13423
|
} : null;
|
|
12084
13424
|
const tools_per_turn = turn_count > 0 ? tools_total / turn_count : 0;
|
|
12085
13425
|
const label = tools_per_turn < 5 ? "rapid" : tools_per_turn < 15 ? "mixed" : "batch";
|
|
@@ -12110,7 +13450,7 @@ function computeInteractionModes(entries) {
|
|
|
12110
13450
|
}
|
|
12111
13451
|
};
|
|
12112
13452
|
}
|
|
12113
|
-
function
|
|
13453
|
+
function truncate6(s, max) {
|
|
12114
13454
|
if (s.length <= max)
|
|
12115
13455
|
return s;
|
|
12116
13456
|
return s.slice(0, max - 1).trimEnd() + "\u2026";
|
|
@@ -12167,7 +13507,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
|
|
|
12167
13507
|
evidence_subagent = {
|
|
12168
13508
|
type: sa.type,
|
|
12169
13509
|
description: sa.description,
|
|
12170
|
-
prompt_preview:
|
|
13510
|
+
prompt_preview: truncate6(sa.prompt_preview, 200)
|
|
12171
13511
|
};
|
|
12172
13512
|
}
|
|
12173
13513
|
const project_display = repEntry ? prettyProject3(repEntry.project) : dd.projects[0]?.display_name ?? "";
|
|
@@ -12178,7 +13518,7 @@ function computeWorkingShapes(dayDigests, entriesByDay = /* @__PURE__ */ new Map
|
|
|
12178
13518
|
outcome: dayOutcome.get(dd.key) ?? null,
|
|
12179
13519
|
helpfulness: dayHelp.get(dd.key) ?? null,
|
|
12180
13520
|
evidence_subagent,
|
|
12181
|
-
evidence_first_user: repEntry?.first_user ?
|
|
13521
|
+
evidence_first_user: repEntry?.first_user ? truncate6(repEntry.first_user, 200) : null,
|
|
12182
13522
|
day_signature: dd.day_signature ?? null
|
|
12183
13523
|
};
|
|
12184
13524
|
});
|
|
@@ -12253,7 +13593,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
|
|
|
12253
13593
|
date: day,
|
|
12254
13594
|
session_id: ref.session_id,
|
|
12255
13595
|
ref_kind: ref.kind,
|
|
12256
|
-
preview:
|
|
13596
|
+
preview: truncate6(ref.preview, 200)
|
|
12257
13597
|
});
|
|
12258
13598
|
}
|
|
12259
13599
|
total_interrupts += signals.comm_style.steering.interrupts;
|
|
@@ -12325,7 +13665,7 @@ function computeInteractionGrammar(dayDigests, entriesByDay = /* @__PURE__ */ ne
|
|
|
12325
13665
|
count: v.count,
|
|
12326
13666
|
days: [...v.days].sort(),
|
|
12327
13667
|
sample_description: v.sample_description,
|
|
12328
|
-
sample_prompt_preview:
|
|
13668
|
+
sample_prompt_preview: truncate6(v.sample_prompt_preview, 200)
|
|
12329
13669
|
})),
|
|
12330
13670
|
threads,
|
|
12331
13671
|
communication_style: {
|
|
@@ -12625,7 +13965,7 @@ var MonthDigestResponseSchema = external_exports.object({
|
|
|
12625
13965
|
}).passthrough();
|
|
12626
13966
|
|
|
12627
13967
|
// ../entries/dist/top-sessions.js
|
|
12628
|
-
var
|
|
13968
|
+
var IDLE_GAP_MS5 = 3 * 60 * 1e3;
|
|
12629
13969
|
var LONG_AUTONOMOUS_MIN = 20;
|
|
12630
13970
|
var N_USER = 150;
|
|
12631
13971
|
var N_FIRST_AGENT = 150;
|
|
@@ -12656,7 +13996,7 @@ function activeMs(timestamps) {
|
|
|
12656
13996
|
let active = 0;
|
|
12657
13997
|
for (let i = 1; i < ts.length; i++) {
|
|
12658
13998
|
const dt = ts[i] - ts[i - 1];
|
|
12659
|
-
if (dt <
|
|
13999
|
+
if (dt < IDLE_GAP_MS5)
|
|
12660
14000
|
active += dt;
|
|
12661
14001
|
}
|
|
12662
14002
|
return active;
|
|
@@ -12830,7 +14170,7 @@ function buildSessionSlice(entry, events, daySignature) {
|
|
|
12830
14170
|
let intEnd = sortedTs[0];
|
|
12831
14171
|
for (let i = 1; i < sortedTs.length; i++) {
|
|
12832
14172
|
const dt = sortedTs[i] - intEnd;
|
|
12833
|
-
if (dt >=
|
|
14173
|
+
if (dt >= IDLE_GAP_MS5) {
|
|
12834
14174
|
intervals.push({
|
|
12835
14175
|
start_min: fmtMin(intStart - sliceStartMs),
|
|
12836
14176
|
end_min: fmtMin(intEnd - sliceStartMs)
|
|
@@ -13711,14 +15051,14 @@ async function getUpdateAvailability() {
|
|
|
13711
15051
|
if (isDevMode()) return null;
|
|
13712
15052
|
const latest = await fetchLatestVersion();
|
|
13713
15053
|
if (latest === null) return {
|
|
13714
|
-
current: "0.
|
|
15054
|
+
current: "0.12.0",
|
|
13715
15055
|
latest: null,
|
|
13716
15056
|
updateAvailable: false
|
|
13717
15057
|
};
|
|
13718
15058
|
return {
|
|
13719
|
-
current: "0.
|
|
15059
|
+
current: "0.12.0",
|
|
13720
15060
|
latest,
|
|
13721
|
-
updateAvailable: shouldUpdate("0.
|
|
15061
|
+
updateAvailable: shouldUpdate("0.12.0", latest)
|
|
13722
15062
|
};
|
|
13723
15063
|
}
|
|
13724
15064
|
|
|
@@ -13728,7 +15068,7 @@ var DAEMON_LOG = cclensPath("daemon.log");
|
|
|
13728
15068
|
var UPDATE_STATE = cclensPath("daemon-update.json");
|
|
13729
15069
|
var WATCHDOG_INTERVAL_MS = 5 * 1e3;
|
|
13730
15070
|
var AUTO_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
13731
|
-
mkdirSync13(
|
|
15071
|
+
mkdirSync13(dirname10(USAGE_LOG3), { recursive: true });
|
|
13732
15072
|
function log2(level, message) {
|
|
13733
15073
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${level.toUpperCase()} ${message}
|
|
13734
15074
|
`;
|
|
@@ -13770,7 +15110,7 @@ var perceptionHandle = setInterval(async () => {
|
|
|
13770
15110
|
}, PERCEPTION_INTERVAL_MS);
|
|
13771
15111
|
function readUpdateState() {
|
|
13772
15112
|
try {
|
|
13773
|
-
return JSON.parse(
|
|
15113
|
+
return JSON.parse(readFileSync15(UPDATE_STATE, "utf8"));
|
|
13774
15114
|
} catch {
|
|
13775
15115
|
return null;
|
|
13776
15116
|
}
|
|
@@ -13790,7 +15130,7 @@ function nextUpdateCheckFromState(nowMs) {
|
|
|
13790
15130
|
}
|
|
13791
15131
|
var nextUpdateCheckAtMs = nextUpdateCheckFromState(Date.now());
|
|
13792
15132
|
function cliEntryPath() {
|
|
13793
|
-
return
|
|
15133
|
+
return join11(dirname10(fileURLToPath(import.meta.url)), "index.js");
|
|
13794
15134
|
}
|
|
13795
15135
|
async function runDaemonUpdateCheck() {
|
|
13796
15136
|
if (process.env.FLEETLENS_DAEMON_AUTO_UPDATE === "0") {
|
|
@@ -13819,7 +15159,7 @@ async function runDaemonUpdateCheck() {
|
|
|
13819
15159
|
return;
|
|
13820
15160
|
}
|
|
13821
15161
|
const entry = cliEntryPath();
|
|
13822
|
-
if (!
|
|
15162
|
+
if (!existsSync13(entry)) {
|
|
13823
15163
|
log2("warn", `update check found ${availability.latest}, but CLI entry is missing at ${entry}`);
|
|
13824
15164
|
return;
|
|
13825
15165
|
}
|
|
@@ -13911,7 +15251,7 @@ function scheduleAfter(now, outcome) {
|
|
|
13911
15251
|
nextPollAtMs = now + currentIntervalMs;
|
|
13912
15252
|
}
|
|
13913
15253
|
function sleep2(ms) {
|
|
13914
|
-
return new Promise((
|
|
15254
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
13915
15255
|
}
|
|
13916
15256
|
async function runLoop() {
|
|
13917
15257
|
while (true) {
|