fleetlens 0.10.2 → 0.10.4
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/build-manifest.json +3 -3
- package/app/apps/web/.next/prerender-manifest.json +3 -3
- 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/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/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/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/chunks/[root-of-the-server]__02px2mk._.js +1 -1
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0vm_41a._.js +1 -1
- package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +6 -6
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0.za3_3._.js +3 -0
- package/app/apps/web/.next/server/chunks/ssr/_0xu2pvc._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_0m67-xi._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/packages_parser_dist_12.endt._.js +1 -1
- package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/app/apps/web/.next/server/pages/500.html +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/app/apps/web/.next/static/chunks/08nun7x9h-ro1.js +14 -0
- package/app/apps/web/lib/changelog-data.generated.ts +1 -1
- package/app/apps/web/package.json +1 -1
- package/app/apps/web/tsconfig.tsbuildinfo +1 -1
- package/dist/daemon-worker.js +387 -58
- package/dist/index.js +269 -189
- package/package.json +6 -1
- package/app/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0s4dg1y._.js +0 -3
- package/app/apps/web/.next/static/chunks/063r4x2.9csh8.js +0 -14
- /package/app/apps/web/.next/static/{XTns3Y6jHWmb7EYKzQi55 → _8He0IMRxt70EDQL1JOFe}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{XTns3Y6jHWmb7EYKzQi55 → _8He0IMRxt70EDQL1JOFe}/_clientMiddlewareManifest.js +0 -0
- /package/app/apps/web/.next/static/{XTns3Y6jHWmb7EYKzQi55 → _8He0IMRxt70EDQL1JOFe}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -1470,6 +1470,12 @@ function decodeProjectName(dir) {
|
|
|
1470
1470
|
return dir;
|
|
1471
1471
|
return "/" + dir.slice(1).replace(/-/g, "/");
|
|
1472
1472
|
}
|
|
1473
|
+
function encodeProjectDir(cwd) {
|
|
1474
|
+
return cwd.replace(/[/.]/g, "-");
|
|
1475
|
+
}
|
|
1476
|
+
function isFleetlensRuntimeDir(projectDir) {
|
|
1477
|
+
return projectDir === FLEETLENS_RUNTIME_PROJECT_DIR;
|
|
1478
|
+
}
|
|
1473
1479
|
async function readJsonlFile(filePath) {
|
|
1474
1480
|
const raw = await fs.readFile(filePath, "utf8");
|
|
1475
1481
|
const out = [];
|
|
@@ -1516,7 +1522,7 @@ async function walkJsonlFiles(root = DEFAULT_ROOT) {
|
|
|
1516
1522
|
} catch {
|
|
1517
1523
|
return [];
|
|
1518
1524
|
}
|
|
1519
|
-
const projectDirs = topEntries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1525
|
+
const projectDirs = topEntries.filter((e) => e.isDirectory() && !isFleetlensRuntimeDir(e.name)).map((e) => e.name);
|
|
1520
1526
|
const perProject = await Promise.all(projectDirs.map(async (projectDir) => {
|
|
1521
1527
|
const projectPath = path.join(root, projectDir);
|
|
1522
1528
|
let files;
|
|
@@ -1997,7 +2003,7 @@ async function findTeamLead(sessionId, opts = {}) {
|
|
|
1997
2003
|
agentName: self.agentName
|
|
1998
2004
|
};
|
|
1999
2005
|
}
|
|
2000
|
-
var DEFAULT_ROOT, metaCache, detailCache, calibrationEventsCache, fileListCache, FILE_LIST_TTL_MS, BLANK_USAGE3, claudeCodeSource;
|
|
2006
|
+
var DEFAULT_ROOT, FLEETLENS_RUNTIME_PROJECT_DIR, metaCache, detailCache, calibrationEventsCache, fileListCache, FILE_LIST_TTL_MS, BLANK_USAGE3, claudeCodeSource;
|
|
2001
2007
|
var init_claude_code = __esm({
|
|
2002
2008
|
"../parser/dist/claude-code.js"() {
|
|
2003
2009
|
"use strict";
|
|
@@ -2007,6 +2013,7 @@ var init_claude_code = __esm({
|
|
|
2007
2013
|
init_agent_metadata();
|
|
2008
2014
|
init_calibration();
|
|
2009
2015
|
DEFAULT_ROOT = path.join(os.homedir(), ".claude", "projects");
|
|
2016
|
+
FLEETLENS_RUNTIME_PROJECT_DIR = encodeProjectDir(path.join(os.homedir(), ".cclens", "runtime"));
|
|
2010
2017
|
metaCache = /* @__PURE__ */ new Map();
|
|
2011
2018
|
detailCache = /* @__PURE__ */ new Map();
|
|
2012
2019
|
calibrationEventsCache = /* @__PURE__ */ new Map();
|
|
@@ -3006,6 +3013,7 @@ __export(fs_exports, {
|
|
|
3006
3013
|
getLatestCodexUsage: () => getLatestCodexUsage,
|
|
3007
3014
|
getSession: () => getSession,
|
|
3008
3015
|
invalidateFile: () => invalidateFile,
|
|
3016
|
+
isFleetlensRuntimeDir: () => isFleetlensRuntimeDir,
|
|
3009
3017
|
listAllSessions: () => listAllSessions,
|
|
3010
3018
|
listCodexSessions: () => listCodexSessions,
|
|
3011
3019
|
listGeminiSessions: () => listGeminiSessions,
|
|
@@ -3720,9 +3728,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
|
|
|
3720
3728
|
console.warn(
|
|
3721
3729
|
` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
|
|
3722
3730
|
);
|
|
3723
|
-
} else if (verify.installedVersion !== "0.10.
|
|
3731
|
+
} else if (verify.installedVersion !== "0.10.4") {
|
|
3724
3732
|
console.log(
|
|
3725
|
-
` \u2192 This process is still running ${"0.10.
|
|
3733
|
+
` \u2192 This process is still running ${"0.10.4"}. Next invocation will use ${verify.installedVersion}.`
|
|
3726
3734
|
);
|
|
3727
3735
|
}
|
|
3728
3736
|
}
|
|
@@ -3753,13 +3761,27 @@ function isDevMode() {
|
|
|
3753
3761
|
const script = process.argv[1] ?? "";
|
|
3754
3762
|
return script.includes("packages/cli/") || script.includes("packages\\cli\\");
|
|
3755
3763
|
}
|
|
3764
|
+
async function getUpdateAvailability() {
|
|
3765
|
+
if (isDevMode()) return null;
|
|
3766
|
+
const latest = await fetchLatestVersion();
|
|
3767
|
+
if (latest === null) return {
|
|
3768
|
+
current: "0.10.4",
|
|
3769
|
+
latest: null,
|
|
3770
|
+
updateAvailable: false
|
|
3771
|
+
};
|
|
3772
|
+
return {
|
|
3773
|
+
current: "0.10.4",
|
|
3774
|
+
latest,
|
|
3775
|
+
updateAvailable: shouldUpdate("0.10.4", latest)
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3756
3778
|
async function checkForUpdate() {
|
|
3757
3779
|
if (isDevMode()) return;
|
|
3758
3780
|
if (process.env.__FLEETLENS_UPDATED === "1" || process.env.__CCLENS_UPDATED === "1") return;
|
|
3759
|
-
const
|
|
3760
|
-
if (latest
|
|
3761
|
-
|
|
3762
|
-
|
|
3781
|
+
const availability = await getUpdateAvailability();
|
|
3782
|
+
if (!availability?.latest) return;
|
|
3783
|
+
if (!availability.updateAvailable) return;
|
|
3784
|
+
const { current, latest } = availability;
|
|
3763
3785
|
console.log(`Updating ${PACKAGE_NAME} ${current} \u2192 ${latest}...`);
|
|
3764
3786
|
await stopRunningServices();
|
|
3765
3787
|
const ok = runNpmInstall();
|
|
@@ -3840,7 +3862,7 @@ async function restartServices(state) {
|
|
|
3840
3862
|
}
|
|
3841
3863
|
async function forceUpdate() {
|
|
3842
3864
|
const latest = await fetchLatestVersion();
|
|
3843
|
-
const current = "0.10.
|
|
3865
|
+
const current = "0.10.4";
|
|
3844
3866
|
if (latest === null) {
|
|
3845
3867
|
console.error("Could not reach npm registry. Check your network.");
|
|
3846
3868
|
process.exit(1);
|
|
@@ -9935,8 +9957,9 @@ exec ${shellEscape(claudeBin)} \\
|
|
|
9935
9957
|
const timeoutMs = args2.timeoutMs ?? 12e4;
|
|
9936
9958
|
let lastReportedKb = -1;
|
|
9937
9959
|
let lastEmittedLength = 0;
|
|
9960
|
+
let transcriptPath;
|
|
9938
9961
|
try {
|
|
9939
|
-
|
|
9962
|
+
transcriptPath = await discoverTranscript(cwd, existingBefore, startMs, timeoutMs, args2.signal);
|
|
9940
9963
|
while (Date.now() - startMs < timeoutMs) {
|
|
9941
9964
|
if (args2.signal?.aborted)
|
|
9942
9965
|
throw new TmuxRunError("aborted");
|
|
@@ -9969,7 +9992,7 @@ exec ${shellEscape(claudeBin)} \\
|
|
|
9969
9992
|
throw new TmuxRunError(`timeout after ${timeoutMs}ms waiting for assistant turn`);
|
|
9970
9993
|
} finally {
|
|
9971
9994
|
args2.signal?.removeEventListener("abort", onAbort);
|
|
9972
|
-
cleanup(cwd, runId, tmuxBin, sessionName);
|
|
9995
|
+
cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath);
|
|
9973
9996
|
}
|
|
9974
9997
|
}
|
|
9975
9998
|
function num(v) {
|
|
@@ -10108,12 +10131,18 @@ function parseTranscript2(path5, defaultModel) {
|
|
|
10108
10131
|
}
|
|
10109
10132
|
return { assembled, inputTokens, outputTokens, modelUsed, done };
|
|
10110
10133
|
}
|
|
10111
|
-
function cleanup(cwd, runId, tmuxBin, sessionName) {
|
|
10134
|
+
function cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath) {
|
|
10112
10135
|
try {
|
|
10113
10136
|
spawnSync2(tmuxBin, ["kill-session", "-t", sessionName], { stdio: "ignore" });
|
|
10114
10137
|
} catch {
|
|
10115
10138
|
}
|
|
10116
10139
|
if (process.env.FLEETLENS_TMUX_KEEP_WRAPPER !== "1") {
|
|
10140
|
+
if (transcriptPath) {
|
|
10141
|
+
try {
|
|
10142
|
+
unlinkSync2(transcriptPath);
|
|
10143
|
+
} catch {
|
|
10144
|
+
}
|
|
10145
|
+
}
|
|
10117
10146
|
for (const f of [`system-${runId}.txt`, `user-${runId}.txt`, `run-${runId}.sh`]) {
|
|
10118
10147
|
try {
|
|
10119
10148
|
unlinkSync2(join7(cwd, f));
|
|
@@ -14617,9 +14646,147 @@ var init_config = __esm({
|
|
|
14617
14646
|
}
|
|
14618
14647
|
});
|
|
14619
14648
|
|
|
14620
|
-
// src/
|
|
14621
|
-
import {
|
|
14649
|
+
// src/team/push.ts
|
|
14650
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
14651
|
+
function readLatestUsageSnapshotForWire(filePath, nowMs = Date.now()) {
|
|
14652
|
+
const raw = latestClaudeCodeSnapshot(filePath);
|
|
14653
|
+
if (!raw) return null;
|
|
14654
|
+
const capturedMs = Date.parse(raw.captured_at);
|
|
14655
|
+
if (Number.isNaN(capturedMs)) return null;
|
|
14656
|
+
if (nowMs - capturedMs > SNAPSHOT_FRESHNESS_MS) return null;
|
|
14657
|
+
const toWire = (w) => w ? { utilization: w.utilization, resetsAt: w.resets_at } : null;
|
|
14658
|
+
return {
|
|
14659
|
+
capturedAt: raw.captured_at,
|
|
14660
|
+
fiveHour: { utilization: raw.five_hour.utilization, resetsAt: raw.five_hour.resets_at },
|
|
14661
|
+
sevenDay: { utilization: raw.seven_day.utilization, resetsAt: raw.seven_day.resets_at },
|
|
14662
|
+
sevenDayOpus: toWire(raw.seven_day_opus),
|
|
14663
|
+
sevenDaySonnet: toWire(raw.seven_day_sonnet),
|
|
14664
|
+
sevenDayOauthApps: toWire(raw.seven_day_oauth_apps),
|
|
14665
|
+
sevenDayCowork: toWire(raw.seven_day_cowork),
|
|
14666
|
+
extraUsage: raw.extra_usage ? {
|
|
14667
|
+
isEnabled: raw.extra_usage.is_enabled,
|
|
14668
|
+
monthlyLimitUsd: raw.extra_usage.monthly_limit,
|
|
14669
|
+
usedCreditsUsd: raw.extra_usage.used_credits,
|
|
14670
|
+
utilization: raw.extra_usage.utilization
|
|
14671
|
+
} : null
|
|
14672
|
+
};
|
|
14673
|
+
}
|
|
14674
|
+
function bucketToRollup(b) {
|
|
14675
|
+
return {
|
|
14676
|
+
day: b.date,
|
|
14677
|
+
agentTimeMs: b.airTimeMs,
|
|
14678
|
+
sessions: b.sessions,
|
|
14679
|
+
toolCalls: b.toolCalls,
|
|
14680
|
+
turns: b.turns,
|
|
14681
|
+
tokens: { ...b.tokens }
|
|
14682
|
+
};
|
|
14683
|
+
}
|
|
14684
|
+
function buildRollupsForRange(sessions, sinceDay) {
|
|
14685
|
+
const buckets = dailyActivity(sessions);
|
|
14686
|
+
const startCounts = /* @__PURE__ */ new Map();
|
|
14687
|
+
for (const s of sessions) {
|
|
14688
|
+
const d = sessionDay(s);
|
|
14689
|
+
if (d) startCounts.set(d, (startCounts.get(d) ?? 0) + 1);
|
|
14690
|
+
}
|
|
14691
|
+
return buckets.filter((b) => !sinceDay || b.date >= sinceDay).map((b) => ({
|
|
14692
|
+
...bucketToRollup(b),
|
|
14693
|
+
sessions: startCounts.get(b.date) ?? 0
|
|
14694
|
+
}));
|
|
14695
|
+
}
|
|
14696
|
+
function buildIngestPayload(rollup, usageSnapshot, planTier, cyclePeaks) {
|
|
14697
|
+
return {
|
|
14698
|
+
ingestId: randomUUID2(),
|
|
14699
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14700
|
+
...rollup ? { dailyRollup: rollup } : {},
|
|
14701
|
+
...usageSnapshot ? { usageSnapshot } : {},
|
|
14702
|
+
...planTier ? { planTier } : {},
|
|
14703
|
+
...cyclePeaks ? { cyclePeaks } : {}
|
|
14704
|
+
};
|
|
14705
|
+
}
|
|
14706
|
+
async function pushToTeamServer(config, payload) {
|
|
14707
|
+
const res = await fetch(`${config.serverUrl}/api/ingest/metrics`, {
|
|
14708
|
+
method: "POST",
|
|
14709
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS),
|
|
14710
|
+
headers: {
|
|
14711
|
+
"Content-Type": "application/json",
|
|
14712
|
+
Authorization: `Bearer ${config.bearerToken}`
|
|
14713
|
+
},
|
|
14714
|
+
body: JSON.stringify(payload)
|
|
14715
|
+
});
|
|
14716
|
+
const body = await res.json().catch(() => null);
|
|
14717
|
+
return { ok: res.ok, status: res.status, body };
|
|
14718
|
+
}
|
|
14719
|
+
var SNAPSHOT_FRESHNESS_MS, POST_TIMEOUT_MS;
|
|
14720
|
+
var init_push = __esm({
|
|
14721
|
+
"src/team/push.ts"() {
|
|
14722
|
+
"use strict";
|
|
14723
|
+
init_dist();
|
|
14724
|
+
init_storage();
|
|
14725
|
+
SNAPSHOT_FRESHNESS_MS = 10 * 60 * 1e3;
|
|
14726
|
+
POST_TIMEOUT_MS = 15e3;
|
|
14727
|
+
}
|
|
14728
|
+
});
|
|
14729
|
+
|
|
14730
|
+
// src/team/queue.ts
|
|
14731
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, appendFileSync as appendFileSync4, statSync as statSync3, mkdirSync as mkdirSync10 } from "node:fs";
|
|
14622
14732
|
import { dirname as dirname9 } from "node:path";
|
|
14733
|
+
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
14734
|
+
mkdirSync10(dirname9(queuePath), { recursive: true });
|
|
14735
|
+
const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14736
|
+
appendFileSync4(queuePath, JSON.stringify(entry) + "\n", "utf8");
|
|
14737
|
+
try {
|
|
14738
|
+
const { size } = statSync3(queuePath);
|
|
14739
|
+
if (size > MAX_SIZE_BYTES) {
|
|
14740
|
+
pruneOldest(queuePath);
|
|
14741
|
+
}
|
|
14742
|
+
} catch {
|
|
14743
|
+
}
|
|
14744
|
+
}
|
|
14745
|
+
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
14746
|
+
let lines;
|
|
14747
|
+
try {
|
|
14748
|
+
lines = readFileSync13(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
14749
|
+
} catch {
|
|
14750
|
+
return [];
|
|
14751
|
+
}
|
|
14752
|
+
const now = Date.now();
|
|
14753
|
+
const valid = [];
|
|
14754
|
+
for (const line of lines) {
|
|
14755
|
+
try {
|
|
14756
|
+
const entry = JSON.parse(line);
|
|
14757
|
+
if (now - new Date(entry.enqueuedAt).getTime() < MAX_AGE_MS) {
|
|
14758
|
+
valid.push(entry);
|
|
14759
|
+
}
|
|
14760
|
+
} catch {
|
|
14761
|
+
}
|
|
14762
|
+
}
|
|
14763
|
+
writeFileSync9(queuePath, "", "utf8");
|
|
14764
|
+
return valid.map((e) => e.payload);
|
|
14765
|
+
}
|
|
14766
|
+
function pruneOldest(queuePath) {
|
|
14767
|
+
let lines;
|
|
14768
|
+
try {
|
|
14769
|
+
lines = readFileSync13(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
14770
|
+
} catch {
|
|
14771
|
+
return;
|
|
14772
|
+
}
|
|
14773
|
+
const keep = lines.slice(Math.floor(lines.length / 2));
|
|
14774
|
+
writeFileSync9(queuePath, keep.join("\n") + "\n", "utf8");
|
|
14775
|
+
}
|
|
14776
|
+
var QUEUE_PATH, MAX_SIZE_BYTES, MAX_AGE_MS;
|
|
14777
|
+
var init_queue2 = __esm({
|
|
14778
|
+
"src/team/queue.ts"() {
|
|
14779
|
+
"use strict";
|
|
14780
|
+
init_fs();
|
|
14781
|
+
QUEUE_PATH = cclensPath("ingest-queue.jsonl");
|
|
14782
|
+
MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
14783
|
+
MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
14784
|
+
}
|
|
14785
|
+
});
|
|
14786
|
+
|
|
14787
|
+
// src/usage/profile.ts
|
|
14788
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
14789
|
+
import { dirname as dirname10 } from "node:path";
|
|
14623
14790
|
function mapRateLimitTier(rateLimitTier) {
|
|
14624
14791
|
switch (rateLimitTier) {
|
|
14625
14792
|
case "default_claude_pro":
|
|
@@ -14661,7 +14828,7 @@ async function fetchProfile(nowMs = Date.now()) {
|
|
|
14661
14828
|
function readCachedProfile(cachePath) {
|
|
14662
14829
|
if (!existsSync12(cachePath)) return null;
|
|
14663
14830
|
try {
|
|
14664
|
-
const raw = JSON.parse(
|
|
14831
|
+
const raw = JSON.parse(readFileSync14(cachePath, "utf8"));
|
|
14665
14832
|
if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
|
|
14666
14833
|
return raw;
|
|
14667
14834
|
} catch {
|
|
@@ -14669,8 +14836,8 @@ function readCachedProfile(cachePath) {
|
|
|
14669
14836
|
}
|
|
14670
14837
|
}
|
|
14671
14838
|
function writeCachedProfile(cachePath, profile, nowMs = Date.now()) {
|
|
14672
|
-
|
|
14673
|
-
|
|
14839
|
+
mkdirSync11(dirname10(cachePath), { recursive: true });
|
|
14840
|
+
writeFileSync10(
|
|
14674
14841
|
cachePath,
|
|
14675
14842
|
JSON.stringify({ fetchedAtMs: nowMs, profile }, null, 2),
|
|
14676
14843
|
{ mode: 384 }
|
|
@@ -14700,11 +14867,6 @@ var init_profile = __esm({
|
|
|
14700
14867
|
});
|
|
14701
14868
|
|
|
14702
14869
|
// src/team/backfill.ts
|
|
14703
|
-
var backfill_exports = {};
|
|
14704
|
-
__export(backfill_exports, {
|
|
14705
|
-
chunk: () => chunk,
|
|
14706
|
-
runTeamBackfill: () => runTeamBackfill
|
|
14707
|
-
});
|
|
14708
14870
|
function rawToWire(raw) {
|
|
14709
14871
|
const win = (w) => w ? { utilization: w.utilization, resetsAt: w.resets_at } : null;
|
|
14710
14872
|
return {
|
|
@@ -14732,6 +14894,7 @@ function chunk(items, size) {
|
|
|
14732
14894
|
async function postBatch(config, snapshots, planTier) {
|
|
14733
14895
|
const res = await fetch(`${config.serverUrl}/api/ingest/usage-history`, {
|
|
14734
14896
|
method: "POST",
|
|
14897
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS2),
|
|
14735
14898
|
headers: {
|
|
14736
14899
|
"Content-Type": "application/json",
|
|
14737
14900
|
Authorization: `Bearer ${config.bearerToken}`
|
|
@@ -14748,13 +14911,35 @@ async function postBatch(config, snapshots, planTier) {
|
|
|
14748
14911
|
status: res.status
|
|
14749
14912
|
};
|
|
14750
14913
|
}
|
|
14751
|
-
|
|
14914
|
+
function isAfterSince(snapshot, sinceCapturedAt) {
|
|
14915
|
+
if (!sinceCapturedAt) return true;
|
|
14916
|
+
const sinceMs = Date.parse(sinceCapturedAt);
|
|
14917
|
+
if (Number.isNaN(sinceMs)) return true;
|
|
14918
|
+
const capturedMs = Date.parse(snapshot.captured_at);
|
|
14919
|
+
return !Number.isNaN(capturedMs) && capturedMs > sinceMs;
|
|
14920
|
+
}
|
|
14921
|
+
function capturedAtMs(snapshot) {
|
|
14922
|
+
const ms = Date.parse(snapshot.captured_at);
|
|
14923
|
+
return Number.isNaN(ms) ? Number.MAX_SAFE_INTEGER : ms;
|
|
14924
|
+
}
|
|
14925
|
+
function latestCapturedAt(snapshots) {
|
|
14926
|
+
let latest = null;
|
|
14927
|
+
for (const s of snapshots) {
|
|
14928
|
+
const ms = Date.parse(s.capturedAt);
|
|
14929
|
+
if (Number.isNaN(ms)) continue;
|
|
14930
|
+
if (!latest || ms > latest.ms) latest = { at: s.capturedAt, ms };
|
|
14931
|
+
}
|
|
14932
|
+
return latest?.at;
|
|
14933
|
+
}
|
|
14934
|
+
async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG3, configOverride, options = {}) {
|
|
14752
14935
|
const config = configOverride === void 0 ? readTeamConfig() : configOverride;
|
|
14753
14936
|
if (!config) {
|
|
14754
14937
|
return { paired: false, sentSnapshots: 0, insertedSnapshots: 0, skippedSnapshots: 0, batches: 0 };
|
|
14755
14938
|
}
|
|
14756
14939
|
const raw = readSnapshots(filePath);
|
|
14757
|
-
const claudeOnly = raw.filter(
|
|
14940
|
+
const claudeOnly = raw.filter(
|
|
14941
|
+
(s) => (!s.agent || s.agent === "claude-code") && isAfterSince(s, options.sinceCapturedAt)
|
|
14942
|
+
).sort((a, b) => capturedAtMs(a) - capturedAtMs(b));
|
|
14758
14943
|
if (claudeOnly.length === 0) {
|
|
14759
14944
|
log("info", "team backfill: no usage snapshots to send");
|
|
14760
14945
|
return { paired: true, sentSnapshots: 0, insertedSnapshots: 0, skippedSnapshots: 0, batches: 0 };
|
|
@@ -14764,6 +14949,7 @@ async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG3, configOverr
|
|
|
14764
14949
|
const planTier = await getPlanTier(PROFILE_CACHE).catch(() => null) ?? void 0;
|
|
14765
14950
|
let inserted = 0;
|
|
14766
14951
|
let skipped = 0;
|
|
14952
|
+
let lastSnapshotAt;
|
|
14767
14953
|
for (let i = 0; i < batches.length; i++) {
|
|
14768
14954
|
const batch = batches[i];
|
|
14769
14955
|
try {
|
|
@@ -14776,11 +14962,13 @@ async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG3, configOverr
|
|
|
14776
14962
|
insertedSnapshots: inserted,
|
|
14777
14963
|
skippedSnapshots: skipped,
|
|
14778
14964
|
batches: i,
|
|
14965
|
+
lastSnapshotAt,
|
|
14779
14966
|
error: `HTTP ${result.status}`
|
|
14780
14967
|
};
|
|
14781
14968
|
}
|
|
14782
14969
|
inserted += result.inserted;
|
|
14783
14970
|
skipped += result.skipped;
|
|
14971
|
+
lastSnapshotAt = latestCapturedAt(batch) ?? lastSnapshotAt;
|
|
14784
14972
|
} catch (err) {
|
|
14785
14973
|
log("warn", `team backfill: batch ${i + 1}/${batches.length} error: ${err.message}`);
|
|
14786
14974
|
return {
|
|
@@ -14789,6 +14977,7 @@ async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG3, configOverr
|
|
|
14789
14977
|
insertedSnapshots: inserted,
|
|
14790
14978
|
skippedSnapshots: skipped,
|
|
14791
14979
|
batches: i,
|
|
14980
|
+
lastSnapshotAt,
|
|
14792
14981
|
error: err.message
|
|
14793
14982
|
};
|
|
14794
14983
|
}
|
|
@@ -14802,10 +14991,11 @@ async function runTeamBackfill(log = noopLog, filePath = USAGE_LOG3, configOverr
|
|
|
14802
14991
|
sentSnapshots: wire.length,
|
|
14803
14992
|
insertedSnapshots: inserted,
|
|
14804
14993
|
skippedSnapshots: skipped,
|
|
14805
|
-
batches: batches.length
|
|
14994
|
+
batches: batches.length,
|
|
14995
|
+
lastSnapshotAt
|
|
14806
14996
|
};
|
|
14807
14997
|
}
|
|
14808
|
-
var USAGE_LOG3, PROFILE_CACHE, BATCH_SIZE, noopLog;
|
|
14998
|
+
var USAGE_LOG3, PROFILE_CACHE, BATCH_SIZE, POST_TIMEOUT_MS2, noopLog;
|
|
14809
14999
|
var init_backfill = __esm({
|
|
14810
15000
|
"src/team/backfill.ts"() {
|
|
14811
15001
|
"use strict";
|
|
@@ -14816,159 +15006,35 @@ var init_backfill = __esm({
|
|
|
14816
15006
|
USAGE_LOG3 = cclensPath("usage.jsonl");
|
|
14817
15007
|
PROFILE_CACHE = cclensPath("profile.json");
|
|
14818
15008
|
BATCH_SIZE = 500;
|
|
15009
|
+
POST_TIMEOUT_MS2 = 15e3;
|
|
14819
15010
|
noopLog = () => {
|
|
14820
15011
|
};
|
|
14821
15012
|
}
|
|
14822
15013
|
});
|
|
14823
15014
|
|
|
14824
|
-
// src/team/push.ts
|
|
14825
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
14826
|
-
function readLatestUsageSnapshotForWire(filePath, nowMs = Date.now()) {
|
|
14827
|
-
const raw = latestClaudeCodeSnapshot(filePath);
|
|
14828
|
-
if (!raw) return null;
|
|
14829
|
-
const capturedMs = Date.parse(raw.captured_at);
|
|
14830
|
-
if (Number.isNaN(capturedMs)) return null;
|
|
14831
|
-
if (nowMs - capturedMs > SNAPSHOT_FRESHNESS_MS) return null;
|
|
14832
|
-
const toWire = (w) => w ? { utilization: w.utilization, resetsAt: w.resets_at } : null;
|
|
14833
|
-
return {
|
|
14834
|
-
capturedAt: raw.captured_at,
|
|
14835
|
-
fiveHour: { utilization: raw.five_hour.utilization, resetsAt: raw.five_hour.resets_at },
|
|
14836
|
-
sevenDay: { utilization: raw.seven_day.utilization, resetsAt: raw.seven_day.resets_at },
|
|
14837
|
-
sevenDayOpus: toWire(raw.seven_day_opus),
|
|
14838
|
-
sevenDaySonnet: toWire(raw.seven_day_sonnet),
|
|
14839
|
-
sevenDayOauthApps: toWire(raw.seven_day_oauth_apps),
|
|
14840
|
-
sevenDayCowork: toWire(raw.seven_day_cowork),
|
|
14841
|
-
extraUsage: raw.extra_usage ? {
|
|
14842
|
-
isEnabled: raw.extra_usage.is_enabled,
|
|
14843
|
-
monthlyLimitUsd: raw.extra_usage.monthly_limit,
|
|
14844
|
-
usedCreditsUsd: raw.extra_usage.used_credits,
|
|
14845
|
-
utilization: raw.extra_usage.utilization
|
|
14846
|
-
} : null
|
|
14847
|
-
};
|
|
14848
|
-
}
|
|
14849
|
-
function bucketToRollup(b) {
|
|
14850
|
-
return {
|
|
14851
|
-
day: b.date,
|
|
14852
|
-
agentTimeMs: b.airTimeMs,
|
|
14853
|
-
sessions: b.sessions,
|
|
14854
|
-
toolCalls: b.toolCalls,
|
|
14855
|
-
turns: b.turns,
|
|
14856
|
-
tokens: { ...b.tokens }
|
|
14857
|
-
};
|
|
14858
|
-
}
|
|
14859
|
-
function buildRollupsForRange(sessions, sinceDay) {
|
|
14860
|
-
const buckets = dailyActivity(sessions);
|
|
14861
|
-
const startCounts = /* @__PURE__ */ new Map();
|
|
14862
|
-
for (const s of sessions) {
|
|
14863
|
-
const d = sessionDay(s);
|
|
14864
|
-
if (d) startCounts.set(d, (startCounts.get(d) ?? 0) + 1);
|
|
14865
|
-
}
|
|
14866
|
-
return buckets.filter((b) => !sinceDay || b.date >= sinceDay).map((b) => ({
|
|
14867
|
-
...bucketToRollup(b),
|
|
14868
|
-
sessions: startCounts.get(b.date) ?? 0
|
|
14869
|
-
}));
|
|
14870
|
-
}
|
|
14871
|
-
function buildIngestPayload(rollup, usageSnapshot, planTier, cyclePeaks) {
|
|
14872
|
-
return {
|
|
14873
|
-
ingestId: randomUUID2(),
|
|
14874
|
-
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14875
|
-
...rollup ? { dailyRollup: rollup } : {},
|
|
14876
|
-
...usageSnapshot ? { usageSnapshot } : {},
|
|
14877
|
-
...planTier ? { planTier } : {},
|
|
14878
|
-
...cyclePeaks ? { cyclePeaks } : {}
|
|
14879
|
-
};
|
|
14880
|
-
}
|
|
14881
|
-
async function pushToTeamServer(config, payload) {
|
|
14882
|
-
const res = await fetch(`${config.serverUrl}/api/ingest/metrics`, {
|
|
14883
|
-
method: "POST",
|
|
14884
|
-
headers: {
|
|
14885
|
-
"Content-Type": "application/json",
|
|
14886
|
-
Authorization: `Bearer ${config.bearerToken}`
|
|
14887
|
-
},
|
|
14888
|
-
body: JSON.stringify(payload)
|
|
14889
|
-
});
|
|
14890
|
-
const body = await res.json().catch(() => null);
|
|
14891
|
-
return { ok: res.ok, status: res.status, body };
|
|
14892
|
-
}
|
|
14893
|
-
var SNAPSHOT_FRESHNESS_MS;
|
|
14894
|
-
var init_push = __esm({
|
|
14895
|
-
"src/team/push.ts"() {
|
|
14896
|
-
"use strict";
|
|
14897
|
-
init_dist();
|
|
14898
|
-
init_storage();
|
|
14899
|
-
SNAPSHOT_FRESHNESS_MS = 10 * 60 * 1e3;
|
|
14900
|
-
}
|
|
14901
|
-
});
|
|
14902
|
-
|
|
14903
|
-
// src/team/queue.ts
|
|
14904
|
-
import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, appendFileSync as appendFileSync4, statSync as statSync3, mkdirSync as mkdirSync11 } from "node:fs";
|
|
14905
|
-
import { dirname as dirname10 } from "node:path";
|
|
14906
|
-
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
14907
|
-
mkdirSync11(dirname10(queuePath), { recursive: true });
|
|
14908
|
-
const entry = { payload, enqueuedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14909
|
-
appendFileSync4(queuePath, JSON.stringify(entry) + "\n", "utf8");
|
|
14910
|
-
try {
|
|
14911
|
-
const { size } = statSync3(queuePath);
|
|
14912
|
-
if (size > MAX_SIZE_BYTES) {
|
|
14913
|
-
pruneOldest(queuePath);
|
|
14914
|
-
}
|
|
14915
|
-
} catch {
|
|
14916
|
-
}
|
|
14917
|
-
}
|
|
14918
|
-
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
14919
|
-
let lines;
|
|
14920
|
-
try {
|
|
14921
|
-
lines = readFileSync14(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
14922
|
-
} catch {
|
|
14923
|
-
return [];
|
|
14924
|
-
}
|
|
14925
|
-
const now = Date.now();
|
|
14926
|
-
const valid = [];
|
|
14927
|
-
for (const line of lines) {
|
|
14928
|
-
try {
|
|
14929
|
-
const entry = JSON.parse(line);
|
|
14930
|
-
if (now - new Date(entry.enqueuedAt).getTime() < MAX_AGE_MS) {
|
|
14931
|
-
valid.push(entry);
|
|
14932
|
-
}
|
|
14933
|
-
} catch {
|
|
14934
|
-
}
|
|
14935
|
-
}
|
|
14936
|
-
writeFileSync10(queuePath, "", "utf8");
|
|
14937
|
-
return valid.map((e) => e.payload);
|
|
14938
|
-
}
|
|
14939
|
-
function pruneOldest(queuePath) {
|
|
14940
|
-
let lines;
|
|
14941
|
-
try {
|
|
14942
|
-
lines = readFileSync14(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
14943
|
-
} catch {
|
|
14944
|
-
return;
|
|
14945
|
-
}
|
|
14946
|
-
const keep = lines.slice(Math.floor(lines.length / 2));
|
|
14947
|
-
writeFileSync10(queuePath, keep.join("\n") + "\n", "utf8");
|
|
14948
|
-
}
|
|
14949
|
-
var QUEUE_PATH, MAX_SIZE_BYTES, MAX_AGE_MS;
|
|
14950
|
-
var init_queue2 = __esm({
|
|
14951
|
-
"src/team/queue.ts"() {
|
|
14952
|
-
"use strict";
|
|
14953
|
-
init_fs();
|
|
14954
|
-
QUEUE_PATH = cclensPath("ingest-queue.jsonl");
|
|
14955
|
-
MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
14956
|
-
MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
14957
|
-
}
|
|
14958
|
-
});
|
|
14959
|
-
|
|
14960
15015
|
// src/team/sync.ts
|
|
14961
15016
|
var sync_exports = {};
|
|
14962
15017
|
__export(sync_exports, {
|
|
14963
15018
|
runTeamSync: () => runTeamSync
|
|
14964
15019
|
});
|
|
14965
|
-
async function runTeamSync(log = noopLog2, configOverride) {
|
|
15020
|
+
async function runTeamSync(log = noopLog2, configOverride, options = {}) {
|
|
14966
15021
|
const config = configOverride === void 0 ? readTeamConfig() : configOverride;
|
|
14967
15022
|
if (!config) return { paired: false, pushed: 0, queued: 0, queuedDrained: 0 };
|
|
14968
15023
|
try {
|
|
14969
15024
|
const { listSessions: listSessions2, loadCalibrationCurve: loadCalibrationCurve2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
14970
15025
|
const { toLocalDay: toLocalDay4 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
14971
15026
|
const today = toLocalDay4(Date.now());
|
|
15027
|
+
let nextConfig = { ...config };
|
|
15028
|
+
const persistConfig = (patch) => {
|
|
15029
|
+
nextConfig = { ...nextConfig, ...patch };
|
|
15030
|
+
writeTeamConfig(nextConfig);
|
|
15031
|
+
};
|
|
15032
|
+
const usageBackfill = await runTeamBackfill(log, USAGE_LOG4, config, {
|
|
15033
|
+
sinceCapturedAt: options.forceUsageBackfill ? void 0 : config.lastSyncedUsageSnapshotAt
|
|
15034
|
+
});
|
|
15035
|
+
if (usageBackfill.lastSnapshotAt) {
|
|
15036
|
+
persistConfig({ lastSyncedUsageSnapshotAt: usageBackfill.lastSnapshotAt });
|
|
15037
|
+
}
|
|
14972
15038
|
const sessions = await listSessions2({ limit: 1e4 });
|
|
14973
15039
|
const rollups = buildRollupsForRange(sessions, config.lastSyncedDay);
|
|
14974
15040
|
const usageSnapshot = readLatestUsageSnapshotForWire(USAGE_LOG4) ?? void 0;
|
|
@@ -14977,15 +15043,15 @@ async function runTeamSync(log = noopLog2, configOverride) {
|
|
|
14977
15043
|
if (rollups.length === 0) {
|
|
14978
15044
|
const hasLiveData = Boolean(usageSnapshot || planTier || cyclePeaks);
|
|
14979
15045
|
if (!hasLiveData) {
|
|
14980
|
-
log("info", "team push: nothing to sync");
|
|
14981
|
-
return { paired: true, pushed: 0, queued: 0, queuedDrained: 0 };
|
|
15046
|
+
if (usageBackfill.sentSnapshots === 0) log("info", "team push: nothing to sync");
|
|
15047
|
+
return { paired: true, pushed: 0, queued: 0, queuedDrained: 0, usageBackfill };
|
|
14982
15048
|
}
|
|
14983
15049
|
const payload = buildIngestPayload(void 0, usageSnapshot, planTier, cyclePeaks);
|
|
14984
15050
|
const result = await pushToTeamServer(config, payload);
|
|
14985
15051
|
if (!result.ok) {
|
|
14986
15052
|
log("warn", `team push (live-only) failed (${result.status}); queueing`);
|
|
14987
15053
|
enqueuePayload(payload);
|
|
14988
|
-
return { paired: true, pushed: 0, queued: 1, queuedDrained: 0 };
|
|
15054
|
+
return { paired: true, pushed: 0, queued: 1, queuedDrained: 0, usageBackfill };
|
|
14989
15055
|
}
|
|
14990
15056
|
let queuedDrained2 = 0;
|
|
14991
15057
|
const backlog = dequeuePayloads();
|
|
@@ -14998,11 +15064,12 @@ async function runTeamSync(log = noopLog2, configOverride) {
|
|
|
14998
15064
|
queuedDrained2++;
|
|
14999
15065
|
}
|
|
15000
15066
|
log("info", `team push ok: live-only (no new daily activity)` + (queuedDrained2 ? `, ${queuedDrained2} queued retried` : ""));
|
|
15001
|
-
return { paired: true, pushed: 1, queued: 0, queuedDrained: queuedDrained2 };
|
|
15067
|
+
return { paired: true, pushed: 1, queued: 0, queuedDrained: queuedDrained2, usageBackfill };
|
|
15002
15068
|
}
|
|
15003
15069
|
let pushed = 0;
|
|
15004
15070
|
let queued = 0;
|
|
15005
15071
|
let failedDay;
|
|
15072
|
+
let lastPushedDay;
|
|
15006
15073
|
for (let i = 0; i < rollups.length; i++) {
|
|
15007
15074
|
const rollup = rollups[i];
|
|
15008
15075
|
const isLatest = i === rollups.length - 1;
|
|
@@ -15023,9 +15090,13 @@ async function runTeamSync(log = noopLog2, configOverride) {
|
|
|
15023
15090
|
break;
|
|
15024
15091
|
}
|
|
15025
15092
|
pushed++;
|
|
15093
|
+
lastPushedDay = rollup.day;
|
|
15094
|
+
}
|
|
15095
|
+
if (failedDay) {
|
|
15096
|
+
if (lastPushedDay) persistConfig({ lastSyncedDay: lastPushedDay });
|
|
15097
|
+
} else {
|
|
15098
|
+
persistConfig({ lastSyncedDay: today });
|
|
15026
15099
|
}
|
|
15027
|
-
const nextConfig = { ...config, lastSyncedDay: today };
|
|
15028
|
-
if (pushed > 0 || !failedDay) writeTeamConfig(nextConfig);
|
|
15029
15100
|
let queuedDrained = 0;
|
|
15030
15101
|
if (!failedDay) {
|
|
15031
15102
|
const backlog = dequeuePayloads();
|
|
@@ -15041,7 +15112,7 @@ async function runTeamSync(log = noopLog2, configOverride) {
|
|
|
15041
15112
|
if (pushed > 0) {
|
|
15042
15113
|
log("info", `team push ok: ${pushed} day${pushed === 1 ? "" : "s"} pushed` + (queuedDrained ? `, ${queuedDrained} queued retried` : "") + (queued ? `, ${queued} queued for retry` : ""));
|
|
15043
15114
|
}
|
|
15044
|
-
return { paired: true, pushed, queued, queuedDrained, failedDay };
|
|
15115
|
+
return { paired: true, pushed, queued, queuedDrained, usageBackfill, failedDay };
|
|
15045
15116
|
} catch (err) {
|
|
15046
15117
|
const message = err.message;
|
|
15047
15118
|
log("warn", `team push error: ${message}`);
|
|
@@ -15115,6 +15186,7 @@ var init_sync = __esm({
|
|
|
15115
15186
|
init_config();
|
|
15116
15187
|
init_push();
|
|
15117
15188
|
init_queue2();
|
|
15189
|
+
init_backfill();
|
|
15118
15190
|
init_profile();
|
|
15119
15191
|
init_fs();
|
|
15120
15192
|
USAGE_LOG4 = cclensPath("usage.jsonl");
|
|
@@ -15158,24 +15230,24 @@ async function joinTeam(args2) {
|
|
|
15158
15230
|
writeTeamConfig(config);
|
|
15159
15231
|
console.log(`Paired with "${data.team.name}" as ${data.user.displayName || data.user.email}`);
|
|
15160
15232
|
console.log(` role: ${data.membership.role}`);
|
|
15161
|
-
console.log("
|
|
15162
|
-
const
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15233
|
+
console.log(" Syncing local history\u2026");
|
|
15234
|
+
const sync = await runTeamSync(void 0, config, { forceUsageBackfill: true });
|
|
15235
|
+
const backfill = sync.usageBackfill;
|
|
15236
|
+
if (backfill?.error) {
|
|
15237
|
+
console.log(` \u26A0 Usage history sync failed: ${backfill.error} \u2014 daemon will retry automatically.`);
|
|
15238
|
+
} else if ((backfill?.insertedSnapshots ?? 0) > 0) {
|
|
15166
15239
|
console.log(
|
|
15167
|
-
` \u2713
|
|
15240
|
+
` \u2713 Synced ${backfill.insertedSnapshots} usage snapshot${backfill.insertedSnapshots === 1 ? "" : "s"} from local history.`
|
|
15168
15241
|
);
|
|
15169
|
-
} else if (backfill
|
|
15170
|
-
console.log(` \u2713 ${backfill.sentSnapshots} snapshots already on server (deduped on capture time).`);
|
|
15242
|
+
} else if ((backfill?.sentSnapshots ?? 0) > 0) {
|
|
15243
|
+
console.log(` \u2713 ${backfill.sentSnapshots} usage snapshots already on server (deduped on capture time).`);
|
|
15171
15244
|
} else {
|
|
15172
15245
|
console.log(" \xB7 No local usage snapshots yet \u2014 daemon will start collecting.");
|
|
15173
15246
|
}
|
|
15174
|
-
const sync = await runTeamSync(void 0, config);
|
|
15175
15247
|
if (sync.error) {
|
|
15176
|
-
console.log(` \u26A0
|
|
15248
|
+
console.log(` \u26A0 Team sync failed: ${sync.error} \u2014 will retry on next daemon cycle.`);
|
|
15177
15249
|
} else if (sync.pushed > 0) {
|
|
15178
|
-
console.log(` \u2713 Synced ${sync.pushed}
|
|
15250
|
+
console.log(` \u2713 Synced ${sync.pushed} activity payload${sync.pushed === 1 ? "" : "s"}.`);
|
|
15179
15251
|
} else {
|
|
15180
15252
|
console.log(" \xB7 No new session activity to push.");
|
|
15181
15253
|
}
|
|
@@ -15185,7 +15257,6 @@ var init_join = __esm({
|
|
|
15185
15257
|
"src/team/join.ts"() {
|
|
15186
15258
|
"use strict";
|
|
15187
15259
|
init_config();
|
|
15188
|
-
init_backfill();
|
|
15189
15260
|
init_sync();
|
|
15190
15261
|
}
|
|
15191
15262
|
});
|
|
@@ -15322,22 +15393,31 @@ async function team(args2) {
|
|
|
15322
15393
|
console.error("Not paired. Run 'fleetlens team join <url> <device-token>' first.");
|
|
15323
15394
|
process.exit(1);
|
|
15324
15395
|
}
|
|
15325
|
-
|
|
15396
|
+
const inserted = outcome.usageBackfill?.insertedSnapshots ?? 0;
|
|
15397
|
+
const madeProgress = outcome.pushed > 0 || outcome.queuedDrained > 0 || inserted > 0;
|
|
15398
|
+
if (outcome.error || outcome.usageBackfill?.error && !madeProgress) process.exit(1);
|
|
15399
|
+
const sent = outcome.usageBackfill?.sentSnapshots ?? 0;
|
|
15400
|
+
const usageChecked = sent > 0 ? `, ${sent} usage snapshot${sent === 1 ? "" : "s"} checked` : "";
|
|
15326
15401
|
console.log(
|
|
15327
|
-
`\u2713 ${outcome.pushed}
|
|
15402
|
+
`\u2713 ${outcome.pushed} activity payload${outcome.pushed === 1 ? "" : "s"} pushed` + usageChecked + (outcome.queuedDrained ? `, ${outcome.queuedDrained} queued retried` : "") + (outcome.queued ? `, ${outcome.queued} queued for retry (will fire next cycle)` : "")
|
|
15328
15403
|
);
|
|
15329
15404
|
break;
|
|
15330
15405
|
}
|
|
15331
15406
|
case "backfill": {
|
|
15332
|
-
const {
|
|
15333
|
-
const outcome = await
|
|
15407
|
+
const { runTeamSync: runTeamSync2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
15408
|
+
const outcome = await runTeamSync2(
|
|
15409
|
+
(level, msg) => console.log(`[${level}] ${msg}`),
|
|
15410
|
+
void 0,
|
|
15411
|
+
{ forceUsageBackfill: true }
|
|
15412
|
+
);
|
|
15334
15413
|
if (!outcome.paired) {
|
|
15335
15414
|
console.error("Not paired. Run 'fleetlens team join <url> <device-token>' first.");
|
|
15336
15415
|
process.exit(1);
|
|
15337
15416
|
}
|
|
15338
|
-
if (outcome.error) process.exit(1);
|
|
15417
|
+
if (outcome.error || outcome.usageBackfill?.error) process.exit(1);
|
|
15418
|
+
const inserted = outcome.usageBackfill?.insertedSnapshots ?? 0;
|
|
15339
15419
|
console.log(
|
|
15340
|
-
`\u2713 ${
|
|
15420
|
+
`\u2713 ${inserted} new snapshot${inserted === 1 ? "" : "s"} loaded` + (outcome.usageBackfill?.skippedSnapshots ? `, ${outcome.usageBackfill.skippedSnapshots} already-known` : "") + (outcome.pushed ? `, ${outcome.pushed} activity payload${outcome.pushed === 1 ? "" : "s"} pushed` : "")
|
|
15341
15421
|
);
|
|
15342
15422
|
break;
|
|
15343
15423
|
}
|
|
@@ -15781,7 +15861,7 @@ async function main() {
|
|
|
15781
15861
|
case "version":
|
|
15782
15862
|
case "--version":
|
|
15783
15863
|
case "-v":
|
|
15784
|
-
console.log(`fleetlens ${"0.10.
|
|
15864
|
+
console.log(`fleetlens ${"0.10.4"}`);
|
|
15785
15865
|
break;
|
|
15786
15866
|
case "help":
|
|
15787
15867
|
case "--help":
|