fleetlens 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/apps/web/.next/BUILD_ID +1 -1
- package/app/apps/web/.next/app-path-routes-manifest.json +1 -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 +6 -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/agent/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/agent/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/events/route.js +3 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/events/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/messages/route.js +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/messages/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/route.js +3 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/stop/route.js +3 -1
- package/app/apps/web/.next/server/app/api/agent/chats/[id]/stop/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/chats/route.js +3 -1
- package/app/apps/web/.next/server/app/api/agent/chats/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/index/route.js +1 -1
- package/app/apps/web/.next/server/app/api/agent/index/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/mcp/route.js +3 -3
- package/app/apps/web/.next/server/app/api/agent/mcp/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/agent/suggestions/route.js +1 -1
- package/app/apps/web/.next/server/app/api/agent/suggestions/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/ask/route.js +1 -1
- package/app/apps/web/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/digest/day/[date]/route.js +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 +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 +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/health/route/app-paths-manifest.json +3 -0
- package/app/apps/web/.next/server/app/api/health/route/build-manifest.json +9 -0
- package/app/apps/web/.next/server/app/api/health/route/server-reference-manifest.json +4 -0
- package/app/apps/web/.next/server/app/api/health/route.js +7 -0
- package/app/apps/web/.next/server/app/api/health/route.js.map +5 -0
- package/app/apps/web/.next/server/app/api/health/route.js.nft.json +1 -0
- package/app/apps/web/.next/server/app/api/health/route_client-reference-manifest.js +3 -0
- package/app/apps/web/.next/server/app/api/pdf/[key]/route.js +1 -1
- package/app/apps/web/.next/server/app/api/pdf/[key]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/projects/open-folder/route.js +1 -1
- package/app/apps/web/.next/server/app/api/projects/open-folder/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/runs/[runId]/stream/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/settings/credentials/route.js +1 -1
- package/app/apps/web/.next/server/app/api/settings/credentials/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/settings/route.js +1 -1
- package/app/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js +1 -1
- package/app/apps/web/.next/server/app/api/team/onboarding/start/route.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/api/team/sync-projects/route.js +1 -1
- package/app/apps/web/.next/server/app/api/team/sync-projects/route.js.nft.json +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/print/[key]/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/print/[key]/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/team/onboarding/page.js.nft.json +1 -1
- package/app/apps/web/.next/server/app/team/onboarding/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 +1 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__038-.1r._.js → [root-of-the-server]__0-09rjv._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0_5tf-2._.js → [root-of-the-server]__01oercw._.js} +5 -5
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__02.51sr._.js +3 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__057w7kr._.js +28 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0pirsh0._.js → [root-of-the-server]__07b5796._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__02puo0u._.js → [root-of-the-server]__07xaqv3._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__06xto5z._.js → [root-of-the-server]__08c24et._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0mvl0qn._.js → [root-of-the-server]__08m2h38._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0mx_9mb._.js → [root-of-the-server]__0c7ght_._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__12iid50._.js → [root-of-the-server]__0l5i8nk._.js} +2 -2
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__04g-b-m._.js → [root-of-the-server]__0mcer3z._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0o9lsie._.js +30 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0367vbv._.js → [root-of-the-server]__0ozooam._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0uf_ch4._.js +28 -0
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0uiom2m._.js +28 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__096_llw._.js → [root-of-the-server]__0usaajs._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0zyh554._.js +3 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__0gvw6dk._.js → [root-of-the-server]__0~4wgaf._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0~~bpcw._.js +3 -0
- package/app/apps/web/.next/server/chunks/{[root-of-the-server]__01~cgp8._.js → [root-of-the-server]__10.g-w1._.js} +2 -2
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__12vjv4c._.js +28 -0
- package/app/apps/web/.next/server/chunks/apps_web__next-internal_server_app_api_health_route_actions_08i7v0h.js +3 -0
- package/app/apps/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0sr4wr_.js +3 -3
- package/app/apps/web/.next/server/chunks/packages_entries_dist_node_0bckr7-.js +19 -19
- package/app/apps/web/.next/server/chunks/ssr/_0k8yioi._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
- package/app/apps/web/.next/server/functions-config-manifest.json +1 -0
- package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/app/apps/web/.next/server/middleware-manifest.json +5 -5
- 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/0ntt~a0712~pv.js +14 -0
- package/app/apps/web/app/api/ask/route.ts +8 -2
- package/app/apps/web/app/api/health/route.ts +12 -0
- package/app/apps/web/lib/agent/run.ts +11 -2
- 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 +377 -50
- package/dist/index.js +204 -114
- package/menubar/Fleetlens.app/Contents/Info.plist +2 -2
- package/menubar/Fleetlens.app/Contents/MacOS/FleetlensMenubar +0 -0
- package/package.json +1 -1
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__02faosk._.js +0 -30
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__02petpy._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__09cgmam._.js +0 -28
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0sbhe0s._.js +0 -3
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0tk8p3d._.js +0 -28
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0u6pamj._.js +0 -28
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__12jomao._.js +0 -28
- package/app/apps/web/.next/static/chunks/03vmnii5njgx2.js +0 -14
- /package/app/apps/web/.next/static/{3_tJh8qOJtVg59IUgLbCS → Shk_TH0B6lHs9cBZekkf5}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{3_tJh8qOJtVg59IUgLbCS → Shk_TH0B6lHs9cBZekkf5}/_clientMiddlewareManifest.js +0 -0
- /package/app/apps/web/.next/static/{3_tJh8qOJtVg59IUgLbCS → Shk_TH0B6lHs9cBZekkf5}/_ssgManifest.js +0 -0
package/dist/daemon-worker.js
CHANGED
|
@@ -6860,11 +6860,204 @@ var init_file_probe = __esm({
|
|
|
6860
6860
|
}
|
|
6861
6861
|
});
|
|
6862
6862
|
|
|
6863
|
-
// src/
|
|
6863
|
+
// src/pid.ts
|
|
6864
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14, unlinkSync as unlinkSync5 } from "node:fs";
|
|
6865
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
6866
|
+
import { dirname as dirname13 } from "node:path";
|
|
6867
|
+
function writePid(filePath, pid, port, version) {
|
|
6868
|
+
mkdirSync14(dirname13(filePath), { recursive: true });
|
|
6869
|
+
let content = String(pid);
|
|
6870
|
+
if (port != null) {
|
|
6871
|
+
content += `:${port}`;
|
|
6872
|
+
if (version) content += `:${version}`;
|
|
6873
|
+
}
|
|
6874
|
+
writeFileSync15(filePath, content, "utf8");
|
|
6875
|
+
}
|
|
6876
|
+
function readPid(filePath) {
|
|
6877
|
+
try {
|
|
6878
|
+
const content = readFileSync21(filePath, "utf8").trim();
|
|
6879
|
+
const [pidStr, portStr, versionStr] = content.split(":");
|
|
6880
|
+
const pid = parseInt(pidStr, 10);
|
|
6881
|
+
if (Number.isNaN(pid)) return null;
|
|
6882
|
+
const port = portStr ? parseInt(portStr, 10) : void 0;
|
|
6883
|
+
return {
|
|
6884
|
+
pid,
|
|
6885
|
+
port: Number.isNaN(port) ? void 0 : port,
|
|
6886
|
+
version: versionStr || void 0
|
|
6887
|
+
};
|
|
6888
|
+
} catch {
|
|
6889
|
+
return null;
|
|
6890
|
+
}
|
|
6891
|
+
}
|
|
6892
|
+
function isProcessAlive(pid, markers) {
|
|
6893
|
+
try {
|
|
6894
|
+
process.kill(pid, 0);
|
|
6895
|
+
} catch {
|
|
6896
|
+
return false;
|
|
6897
|
+
}
|
|
6898
|
+
if (!markers || markers.length === 0) return true;
|
|
6899
|
+
try {
|
|
6900
|
+
const cmd = execFileSync3("ps", ["-p", String(pid), "-o", "command="], {
|
|
6901
|
+
encoding: "utf8"
|
|
6902
|
+
}).trim();
|
|
6903
|
+
return markers.some((m) => cmd.includes(m));
|
|
6904
|
+
} catch {
|
|
6905
|
+
return false;
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
function cleanStalePid(filePath, markers) {
|
|
6909
|
+
const entry = readPid(filePath);
|
|
6910
|
+
if (entry === null) return false;
|
|
6911
|
+
if (isProcessAlive(entry.pid, markers)) return false;
|
|
6912
|
+
try {
|
|
6913
|
+
unlinkSync5(filePath);
|
|
6914
|
+
} catch {
|
|
6915
|
+
}
|
|
6916
|
+
return true;
|
|
6917
|
+
}
|
|
6918
|
+
function removePid(filePath) {
|
|
6919
|
+
try {
|
|
6920
|
+
unlinkSync5(filePath);
|
|
6921
|
+
} catch {
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
var init_pid = __esm({
|
|
6925
|
+
"src/pid.ts"() {
|
|
6926
|
+
"use strict";
|
|
6927
|
+
}
|
|
6928
|
+
});
|
|
6929
|
+
|
|
6930
|
+
// src/server.ts
|
|
6864
6931
|
import { spawn as spawn3 } from "node:child_process";
|
|
6865
|
-
import {
|
|
6866
|
-
import { dirname as dirname12, join as join13 } from "node:path";
|
|
6932
|
+
import { join as join14, dirname as dirname14 } from "node:path";
|
|
6867
6933
|
import { fileURLToPath } from "node:url";
|
|
6934
|
+
import { existsSync as existsSync20, realpathSync as realpathSync3, readFileSync as readFileSync22 } from "node:fs";
|
|
6935
|
+
import { homedir as homedir7 } from "node:os";
|
|
6936
|
+
function appDir() {
|
|
6937
|
+
const here = dirname14(fileURLToPath(import.meta.url));
|
|
6938
|
+
return join14(here, "..", "app", "apps", "web");
|
|
6939
|
+
}
|
|
6940
|
+
function cliBinRealPath() {
|
|
6941
|
+
const argv1 = process.argv[1] ?? "";
|
|
6942
|
+
try {
|
|
6943
|
+
return realpathSync3(argv1);
|
|
6944
|
+
} catch {
|
|
6945
|
+
return argv1;
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
function onDiskVersion() {
|
|
6949
|
+
try {
|
|
6950
|
+
const here = dirname14(fileURLToPath(import.meta.url));
|
|
6951
|
+
const pkg = JSON.parse(readFileSync22(join14(here, "..", "package.json"), "utf8"));
|
|
6952
|
+
return pkg.version ?? "1.0.3";
|
|
6953
|
+
} catch {
|
|
6954
|
+
return "1.0.3";
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6957
|
+
function getServerStatus() {
|
|
6958
|
+
cleanStalePid(PID_FILE, SERVER_MARKERS);
|
|
6959
|
+
const entry = readPid(PID_FILE);
|
|
6960
|
+
if (entry !== null && isProcessAlive(entry.pid, SERVER_MARKERS)) {
|
|
6961
|
+
return { running: true, pid: entry.pid, port: entry.port ?? DEFAULT_PORT, version: entry.version };
|
|
6962
|
+
}
|
|
6963
|
+
return { running: false };
|
|
6964
|
+
}
|
|
6965
|
+
async function startServer(opts = {}) {
|
|
6966
|
+
const port = opts.port ?? (parseInt(process.env.CCLENS_PORT ?? "", 10) || DEFAULT_PORT);
|
|
6967
|
+
const serverJs = join14(appDir(), "server.js");
|
|
6968
|
+
if (!existsSync20(serverJs)) {
|
|
6969
|
+
throw new Error(`Server not found at ${serverJs}. Reinstall with: npm install -g fleetlens`);
|
|
6970
|
+
}
|
|
6971
|
+
const portInUse = await checkPort(port);
|
|
6972
|
+
if (portInUse) {
|
|
6973
|
+
throw new Error(`Port ${port} is in use. Use --port to specify a different port.`);
|
|
6974
|
+
}
|
|
6975
|
+
const dataDir = join14(homedir7(), ".claude", "projects");
|
|
6976
|
+
const child = spawn3(process.execPath, [serverJs], {
|
|
6977
|
+
detached: true,
|
|
6978
|
+
stdio: "ignore",
|
|
6979
|
+
env: {
|
|
6980
|
+
...process.env,
|
|
6981
|
+
PORT: String(port),
|
|
6982
|
+
HOSTNAME: "localhost",
|
|
6983
|
+
CCLENS_DATA_DIR: dataDir,
|
|
6984
|
+
FLEETLENS_CLI_BIN: cliBinRealPath(),
|
|
6985
|
+
FLEETLENS_WEB_START_DAEMON: opts.autoStartDaemon === false ? "0" : "1"
|
|
6986
|
+
},
|
|
6987
|
+
cwd: appDir()
|
|
6988
|
+
});
|
|
6989
|
+
child.unref();
|
|
6990
|
+
const pid = child.pid;
|
|
6991
|
+
writePid(PID_FILE, pid, port, onDiskVersion());
|
|
6992
|
+
await waitForHealth(`http://localhost:${port}`, 3e4);
|
|
6993
|
+
return { pid, port };
|
|
6994
|
+
}
|
|
6995
|
+
async function probeServerHealth(port, timeoutMs) {
|
|
6996
|
+
try {
|
|
6997
|
+
await fetch(`http://localhost:${port}/api/health`, {
|
|
6998
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
6999
|
+
});
|
|
7000
|
+
return true;
|
|
7001
|
+
} catch {
|
|
7002
|
+
return false;
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
async function restartWedgedServer(pid, port) {
|
|
7006
|
+
try {
|
|
7007
|
+
process.kill(pid, "SIGKILL");
|
|
7008
|
+
} catch {
|
|
7009
|
+
}
|
|
7010
|
+
removePid(PID_FILE);
|
|
7011
|
+
await waitForPortFree(port, 5e3);
|
|
7012
|
+
return startServer({ port });
|
|
7013
|
+
}
|
|
7014
|
+
async function checkPort(port) {
|
|
7015
|
+
const { createServer } = await import("node:net");
|
|
7016
|
+
return new Promise((resolve4) => {
|
|
7017
|
+
const server = createServer();
|
|
7018
|
+
server.once("error", () => resolve4(true));
|
|
7019
|
+
server.once("listening", () => {
|
|
7020
|
+
server.close(() => resolve4(false));
|
|
7021
|
+
});
|
|
7022
|
+
server.listen(port, "localhost");
|
|
7023
|
+
});
|
|
7024
|
+
}
|
|
7025
|
+
async function waitForPortFree(port, timeoutMs) {
|
|
7026
|
+
const start = Date.now();
|
|
7027
|
+
while (Date.now() - start < timeoutMs) {
|
|
7028
|
+
if (!await checkPort(port)) return;
|
|
7029
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
7030
|
+
}
|
|
7031
|
+
}
|
|
7032
|
+
async function waitForHealth(url, timeoutMs) {
|
|
7033
|
+
const start = Date.now();
|
|
7034
|
+
while (Date.now() - start < timeoutMs) {
|
|
7035
|
+
try {
|
|
7036
|
+
const res = await fetch(url);
|
|
7037
|
+
if (res.ok) return;
|
|
7038
|
+
} catch {
|
|
7039
|
+
}
|
|
7040
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
7041
|
+
}
|
|
7042
|
+
throw new Error(`Server did not become healthy within ${timeoutMs / 1e3}s`);
|
|
7043
|
+
}
|
|
7044
|
+
var PID_FILE, DEFAULT_PORT, SERVER_MARKERS;
|
|
7045
|
+
var init_server = __esm({
|
|
7046
|
+
"src/server.ts"() {
|
|
7047
|
+
"use strict";
|
|
7048
|
+
init_pid();
|
|
7049
|
+
init_fs();
|
|
7050
|
+
PID_FILE = cclensPath("pid");
|
|
7051
|
+
DEFAULT_PORT = 3321;
|
|
7052
|
+
SERVER_MARKERS = ["next-server", "server.js"];
|
|
7053
|
+
}
|
|
7054
|
+
});
|
|
7055
|
+
|
|
7056
|
+
// src/daemon-worker.ts
|
|
7057
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
7058
|
+
import { closeSync, existsSync as existsSync21, mkdirSync as mkdirSync15, openSync, readFileSync as readFileSync23, writeFileSync as writeFileSync16 } from "node:fs";
|
|
7059
|
+
import { dirname as dirname15, join as join15 } from "node:path";
|
|
7060
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6868
7061
|
|
|
6869
7062
|
// src/usage/token.ts
|
|
6870
7063
|
import { execFileSync } from "node:child_process";
|
|
@@ -7192,8 +7385,8 @@ async function refreshAccessToken(entry) {
|
|
|
7192
7385
|
break;
|
|
7193
7386
|
}
|
|
7194
7387
|
}
|
|
7195
|
-
const { writeFileSync:
|
|
7196
|
-
|
|
7388
|
+
const { writeFileSync: writeFileSync17 } = await import("node:fs");
|
|
7389
|
+
writeFileSync17(p, JSON.stringify(raw, null, 2), "utf8");
|
|
7197
7390
|
} catch {
|
|
7198
7391
|
}
|
|
7199
7392
|
return j.access_token;
|
|
@@ -9111,7 +9304,7 @@ function buildIngestPayload(inputs) {
|
|
|
9111
9304
|
return {
|
|
9112
9305
|
ingestId: randomUUID(),
|
|
9113
9306
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9114
|
-
cliVersion: "1.0.
|
|
9307
|
+
cliVersion: "1.0.3",
|
|
9115
9308
|
...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
9116
9309
|
...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
|
|
9117
9310
|
...richRollup ? { richRollup } : {},
|
|
@@ -14384,14 +14577,56 @@ var ENRICHMENT_SYSTEM_PROMPT = SYSTEM_PROMPT;
|
|
|
14384
14577
|
// ../entries/dist/llm-runner.js
|
|
14385
14578
|
init_fs();
|
|
14386
14579
|
import { spawn as spawn2 } from "node:child_process";
|
|
14387
|
-
import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync5, writeFileSync as writeFileSync12, existsSync as
|
|
14388
|
-
import { join as
|
|
14580
|
+
import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync5, writeFileSync as writeFileSync12, existsSync as existsSync16 } from "node:fs";
|
|
14581
|
+
import { join as join13 } from "node:path";
|
|
14389
14582
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
14390
14583
|
|
|
14391
|
-
// ../entries/dist/
|
|
14392
|
-
import {
|
|
14393
|
-
import { join as join11 } from "node:path";
|
|
14584
|
+
// ../entries/dist/claude-bin.js
|
|
14585
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
14586
|
+
import { join as join11, dirname as dirname11, delimiter } from "node:path";
|
|
14394
14587
|
import { homedir as homedir5 } from "node:os";
|
|
14588
|
+
function resolveClaudeBin(opts = {}) {
|
|
14589
|
+
const env = opts.env ?? process.env;
|
|
14590
|
+
const home = opts.home ?? homedir5();
|
|
14591
|
+
const execPath = opts.execPath ?? process.execPath;
|
|
14592
|
+
const exists = opts.exists ?? existsSync14;
|
|
14593
|
+
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
14594
|
+
if (!dir)
|
|
14595
|
+
continue;
|
|
14596
|
+
const onPath = join11(dir, "claude");
|
|
14597
|
+
if (exists(onPath))
|
|
14598
|
+
return onPath;
|
|
14599
|
+
}
|
|
14600
|
+
return [
|
|
14601
|
+
join11(home, ".local", "bin", "claude"),
|
|
14602
|
+
// native installer
|
|
14603
|
+
join11(home, ".claude", "local", "claude"),
|
|
14604
|
+
// legacy local install
|
|
14605
|
+
join11(dirname11(execPath), "claude"),
|
|
14606
|
+
// npm -g, beside the node running us
|
|
14607
|
+
"/opt/homebrew/bin/claude",
|
|
14608
|
+
"/usr/local/bin/claude"
|
|
14609
|
+
].find(exists);
|
|
14610
|
+
}
|
|
14611
|
+
function claudeSpawnEnv(bin, env = process.env, execPath = process.execPath) {
|
|
14612
|
+
const parts = (env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
14613
|
+
for (const dir of [dirname11(execPath), dirname11(bin)]) {
|
|
14614
|
+
if (!parts.includes(dir))
|
|
14615
|
+
parts.unshift(dir);
|
|
14616
|
+
}
|
|
14617
|
+
return { ...env, PATH: parts.join(delimiter) };
|
|
14618
|
+
}
|
|
14619
|
+
var ClaudeBinNotFoundError = class extends Error {
|
|
14620
|
+
constructor() {
|
|
14621
|
+
super("claude CLI not found. Looked on PATH and in ~/.local/bin, ~/.claude/local, the npm global bin, homebrew, and /usr/local/bin. Install it, or if Fleetlens was started at login, restart it from a terminal: fleetlens stop && fleetlens start");
|
|
14622
|
+
this.name = "ClaudeBinNotFoundError";
|
|
14623
|
+
}
|
|
14624
|
+
};
|
|
14625
|
+
|
|
14626
|
+
// ../entries/dist/tmux-runner.js
|
|
14627
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as existsSync15, readdirSync as readdirSync5, realpathSync as realpathSync2, readFileSync as readFileSync17, unlinkSync as unlinkSync3, renameSync as renameSync5 } from "node:fs";
|
|
14628
|
+
import { join as join12 } from "node:path";
|
|
14629
|
+
import { homedir as homedir6 } from "node:os";
|
|
14395
14630
|
import { spawnSync } from "node:child_process";
|
|
14396
14631
|
var TmuxUnavailableError = class extends Error {
|
|
14397
14632
|
constructor(message) {
|
|
@@ -14414,18 +14649,18 @@ function which(bin) {
|
|
|
14414
14649
|
function tmuxRunnerAvailable() {
|
|
14415
14650
|
if (!which("tmux"))
|
|
14416
14651
|
return { ok: false, reason: "tmux not on PATH" };
|
|
14417
|
-
if (!
|
|
14418
|
-
return { ok: false, reason: "claude not
|
|
14652
|
+
if (!resolveClaudeBin())
|
|
14653
|
+
return { ok: false, reason: "claude CLI not found" };
|
|
14419
14654
|
return { ok: true };
|
|
14420
14655
|
}
|
|
14421
14656
|
function runtimeCwd() {
|
|
14422
|
-
const dir =
|
|
14423
|
-
if (!
|
|
14657
|
+
const dir = join12(homedir6(), ".cclens", "runtime");
|
|
14658
|
+
if (!existsSync15(dir))
|
|
14424
14659
|
mkdirSync10(dir, { recursive: true });
|
|
14425
14660
|
return realpathSync2(dir);
|
|
14426
14661
|
}
|
|
14427
14662
|
function ensureRuntimeCwdTrusted(cwd) {
|
|
14428
|
-
const cfgPath =
|
|
14663
|
+
const cfgPath = join12(homedir6(), ".claude.json");
|
|
14429
14664
|
let cfg;
|
|
14430
14665
|
try {
|
|
14431
14666
|
cfg = JSON.parse(readFileSync17(cfgPath, "utf8"));
|
|
@@ -14462,18 +14697,18 @@ async function runClaudeUnderTmuxImpl(args) {
|
|
|
14462
14697
|
const tmuxBin = args.tmuxBin ?? which("tmux");
|
|
14463
14698
|
if (!tmuxBin)
|
|
14464
14699
|
throw new TmuxUnavailableError("tmux not on PATH");
|
|
14465
|
-
const claudeBin = args.claudeBin ??
|
|
14700
|
+
const claudeBin = args.claudeBin ?? resolveClaudeBin();
|
|
14466
14701
|
if (!claudeBin)
|
|
14467
|
-
throw new TmuxUnavailableError("claude not
|
|
14702
|
+
throw new TmuxUnavailableError("claude CLI not found");
|
|
14468
14703
|
if (args.signal?.aborted)
|
|
14469
14704
|
throw new TmuxRunError("aborted before spawn");
|
|
14470
14705
|
const cwd = runtimeCwd();
|
|
14471
14706
|
ensureRuntimeCwdTrusted(cwd);
|
|
14472
14707
|
const runId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
14473
14708
|
const sessionName = `cclens-${runId}`;
|
|
14474
|
-
const systemFile =
|
|
14475
|
-
const userFile =
|
|
14476
|
-
const wrapper =
|
|
14709
|
+
const systemFile = join12(cwd, `system-${runId}.txt`);
|
|
14710
|
+
const userFile = join12(cwd, `user-${runId}.txt`);
|
|
14711
|
+
const wrapper = join12(cwd, `run-${runId}.sh`);
|
|
14477
14712
|
writeFileSync11(systemFile, args.systemPrompt);
|
|
14478
14713
|
writeFileSync11(userFile, args.reminder ? `${args.userPrompt}
|
|
14479
14714
|
|
|
@@ -14492,10 +14727,10 @@ exec ${shellEscape(claudeBin)} \\
|
|
|
14492
14727
|
"$USR"
|
|
14493
14728
|
`, { mode: 493 });
|
|
14494
14729
|
const existingBefore = snapshotAllTranscripts();
|
|
14495
|
-
const
|
|
14496
|
-
if (
|
|
14730
|
+
const spawn5 = spawnSync(tmuxBin, ["new-session", "-d", "-s", sessionName, "-x", "140", "-y", "50", "-c", cwd, wrapper], { encoding: "utf8" });
|
|
14731
|
+
if (spawn5.status !== 0) {
|
|
14497
14732
|
cleanup(cwd, runId, tmuxBin, sessionName);
|
|
14498
|
-
throw new TmuxRunError(`tmux new-session failed: ${
|
|
14733
|
+
throw new TmuxRunError(`tmux new-session failed: ${spawn5.stderr.trim()}`);
|
|
14499
14734
|
}
|
|
14500
14735
|
const onAbort = () => {
|
|
14501
14736
|
try {
|
|
@@ -14552,7 +14787,7 @@ function num(v) {
|
|
|
14552
14787
|
function sleep(ms) {
|
|
14553
14788
|
return new Promise((r) => setTimeout(r, ms));
|
|
14554
14789
|
}
|
|
14555
|
-
var PROJECTS_ROOT = () =>
|
|
14790
|
+
var PROJECTS_ROOT = () => join12(homedir6(), ".claude", "projects");
|
|
14556
14791
|
function snapshotAllTranscripts() {
|
|
14557
14792
|
const out = /* @__PURE__ */ new Set();
|
|
14558
14793
|
const root = PROJECTS_ROOT();
|
|
@@ -14563,7 +14798,7 @@ function snapshotAllTranscripts() {
|
|
|
14563
14798
|
return out;
|
|
14564
14799
|
}
|
|
14565
14800
|
for (const sub of subs) {
|
|
14566
|
-
const dir =
|
|
14801
|
+
const dir = join12(root, sub);
|
|
14567
14802
|
let files;
|
|
14568
14803
|
try {
|
|
14569
14804
|
files = readdirSync5(dir);
|
|
@@ -14572,7 +14807,7 @@ function snapshotAllTranscripts() {
|
|
|
14572
14807
|
}
|
|
14573
14808
|
for (const f of files) {
|
|
14574
14809
|
if (f.endsWith(".jsonl"))
|
|
14575
|
-
out.add(
|
|
14810
|
+
out.add(join12(dir, f));
|
|
14576
14811
|
}
|
|
14577
14812
|
}
|
|
14578
14813
|
return out;
|
|
@@ -14613,7 +14848,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
14613
14848
|
subs = [];
|
|
14614
14849
|
}
|
|
14615
14850
|
for (const sub of subs) {
|
|
14616
|
-
const dir =
|
|
14851
|
+
const dir = join12(root, sub);
|
|
14617
14852
|
let files;
|
|
14618
14853
|
try {
|
|
14619
14854
|
files = readdirSync5(dir);
|
|
@@ -14623,7 +14858,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
14623
14858
|
for (const f of files) {
|
|
14624
14859
|
if (!f.endsWith(".jsonl"))
|
|
14625
14860
|
continue;
|
|
14626
|
-
const full =
|
|
14861
|
+
const full = join12(dir, f);
|
|
14627
14862
|
if (existingBefore.has(full))
|
|
14628
14863
|
continue;
|
|
14629
14864
|
if (readJsonlCwd(full) === targetCwd)
|
|
@@ -14697,7 +14932,7 @@ function cleanup(cwd, runId, tmuxBin, sessionName, transcriptPath) {
|
|
|
14697
14932
|
}
|
|
14698
14933
|
for (const f of [`system-${runId}.txt`, `user-${runId}.txt`, `run-${runId}.sh`]) {
|
|
14699
14934
|
try {
|
|
14700
|
-
unlinkSync3(
|
|
14935
|
+
unlinkSync3(join12(cwd, f));
|
|
14701
14936
|
} catch {
|
|
14702
14937
|
}
|
|
14703
14938
|
}
|
|
@@ -14712,7 +14947,7 @@ function shellEscape(s) {
|
|
|
14712
14947
|
// ../entries/dist/llm-runner.js
|
|
14713
14948
|
var RUNS_DIR = cclensPath("llm-runs");
|
|
14714
14949
|
function ensureRunsDir() {
|
|
14715
|
-
if (!
|
|
14950
|
+
if (!existsSync16(RUNS_DIR)) {
|
|
14716
14951
|
try {
|
|
14717
14952
|
mkdirSync11(RUNS_DIR, { recursive: true });
|
|
14718
14953
|
} catch {
|
|
@@ -14741,7 +14976,7 @@ function newRunId(kind) {
|
|
|
14741
14976
|
return `${ts}_${kind}_${short}`;
|
|
14742
14977
|
}
|
|
14743
14978
|
function tracePath(runId) {
|
|
14744
|
-
return
|
|
14979
|
+
return join13(RUNS_DIR, `${runId}.jsonl`);
|
|
14745
14980
|
}
|
|
14746
14981
|
function safeAppend(path11, line) {
|
|
14747
14982
|
try {
|
|
@@ -14884,7 +15119,14 @@ function runClaudePrintMode(args) {
|
|
|
14884
15119
|
"--append-system-prompt",
|
|
14885
15120
|
args.systemPrompt
|
|
14886
15121
|
];
|
|
14887
|
-
const
|
|
15122
|
+
const claudeBin = resolveClaudeBin();
|
|
15123
|
+
if (!claudeBin) {
|
|
15124
|
+
const err = new ClaudeBinNotFoundError();
|
|
15125
|
+
safeAppend(trace, JSON.stringify({ _meta: { type: "spawn_error", run_id: runId, ts: (/* @__PURE__ */ new Date()).toISOString(), error: err.message } }) + "\n");
|
|
15126
|
+
reject(err);
|
|
15127
|
+
return;
|
|
15128
|
+
}
|
|
15129
|
+
const proc = spawn2(claudeBin, claudeArgs, { stdio: ["pipe", "pipe", "pipe"], env: claudeSpawnEnv(claudeBin) });
|
|
14888
15130
|
safeAppend(trace, JSON.stringify({ _meta: { type: "spawned", run_id: runId, pid: proc.pid } }) + "\n");
|
|
14889
15131
|
const stdinPayload = args.reminder ? `${args.userPrompt}
|
|
14890
15132
|
|
|
@@ -15140,8 +15382,8 @@ function applyEnrichmentError(entry, errorMessage, model, costUsd, generatedAt,
|
|
|
15140
15382
|
|
|
15141
15383
|
// ../entries/dist/budget.js
|
|
15142
15384
|
init_fs();
|
|
15143
|
-
import { appendFileSync as appendFileSync6, readFileSync as readFileSync18, existsSync as
|
|
15144
|
-
import { dirname as
|
|
15385
|
+
import { appendFileSync as appendFileSync6, readFileSync as readFileSync18, existsSync as existsSync17, mkdirSync as mkdirSync12 } from "node:fs";
|
|
15386
|
+
import { dirname as dirname12 } from "node:path";
|
|
15145
15387
|
var spendPathCached = null;
|
|
15146
15388
|
function spendPath() {
|
|
15147
15389
|
if (spendPathCached)
|
|
@@ -15151,12 +15393,12 @@ function spendPath() {
|
|
|
15151
15393
|
}
|
|
15152
15394
|
function appendSpend(record) {
|
|
15153
15395
|
const p = spendPath();
|
|
15154
|
-
mkdirSync12(
|
|
15396
|
+
mkdirSync12(dirname12(p), { recursive: true });
|
|
15155
15397
|
appendFileSync6(p, JSON.stringify(record) + "\n", { encoding: "utf8" });
|
|
15156
15398
|
}
|
|
15157
15399
|
function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
15158
15400
|
const p = spendPath();
|
|
15159
|
-
if (!
|
|
15401
|
+
if (!existsSync17(p))
|
|
15160
15402
|
return 0;
|
|
15161
15403
|
const year = now.getUTCFullYear();
|
|
15162
15404
|
const month = now.getUTCMonth();
|
|
@@ -15183,7 +15425,7 @@ function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
|
15183
15425
|
|
|
15184
15426
|
// ../entries/dist/pipeline-lock.js
|
|
15185
15427
|
init_fs();
|
|
15186
|
-
import { writeFileSync as writeFileSync13, unlinkSync as unlinkSync4, existsSync as
|
|
15428
|
+
import { writeFileSync as writeFileSync13, unlinkSync as unlinkSync4, existsSync as existsSync18, readFileSync as readFileSync19, statSync as statSync7 } from "node:fs";
|
|
15187
15429
|
var STALE_MS2 = 60 * 1e3;
|
|
15188
15430
|
var HEARTBEAT_MS = 30 * 1e3;
|
|
15189
15431
|
var lockPathCached = null;
|
|
@@ -15229,7 +15471,7 @@ function pidAlive(pid) {
|
|
|
15229
15471
|
}
|
|
15230
15472
|
function interactiveLockFresh(nowMs) {
|
|
15231
15473
|
const p = lockPath();
|
|
15232
|
-
if (!
|
|
15474
|
+
if (!existsSync18(p))
|
|
15233
15475
|
return false;
|
|
15234
15476
|
try {
|
|
15235
15477
|
const mtime = statSync7(p).mtimeMs;
|
|
@@ -15250,7 +15492,7 @@ function interactiveLockFresh(nowMs) {
|
|
|
15250
15492
|
var THIRTY_MIN_MS = 30 * 60 * 1e3;
|
|
15251
15493
|
|
|
15252
15494
|
// ../entries/dist/settings.js
|
|
15253
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, renameSync as renameSync6, chmodSync as chmodSync2, mkdirSync as mkdirSync13, existsSync as
|
|
15495
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, renameSync as renameSync6, chmodSync as chmodSync2, mkdirSync as mkdirSync13, existsSync as existsSync19 } from "node:fs";
|
|
15254
15496
|
init_fs();
|
|
15255
15497
|
var DEFAULT_SETTINGS = {
|
|
15256
15498
|
ai_features: {
|
|
@@ -15282,7 +15524,7 @@ function fromDisk(d) {
|
|
|
15282
15524
|
}
|
|
15283
15525
|
function readSettings() {
|
|
15284
15526
|
const p = settingsPath();
|
|
15285
|
-
if (!
|
|
15527
|
+
if (!existsSync19(p))
|
|
15286
15528
|
return DEFAULT_SETTINGS;
|
|
15287
15529
|
try {
|
|
15288
15530
|
const raw = readFileSync20(p, "utf8");
|
|
@@ -18045,30 +18287,73 @@ async function getUpdateAvailability() {
|
|
|
18045
18287
|
if (isDevMode()) return null;
|
|
18046
18288
|
const latest = await fetchLatestVersion();
|
|
18047
18289
|
if (latest === null) return {
|
|
18048
|
-
current: "1.0.
|
|
18290
|
+
current: "1.0.3",
|
|
18049
18291
|
latest: null,
|
|
18050
18292
|
updateAvailable: false
|
|
18051
18293
|
};
|
|
18052
18294
|
return {
|
|
18053
|
-
current: "1.0.
|
|
18295
|
+
current: "1.0.3",
|
|
18054
18296
|
latest,
|
|
18055
|
-
updateAvailable: shouldUpdate("1.0.
|
|
18297
|
+
updateAvailable: shouldUpdate("1.0.3", latest)
|
|
18056
18298
|
};
|
|
18057
18299
|
}
|
|
18058
18300
|
|
|
18301
|
+
// src/daemon-worker.ts
|
|
18302
|
+
init_server();
|
|
18303
|
+
|
|
18304
|
+
// src/watchdog.ts
|
|
18305
|
+
var FAILURE_THRESHOLD = 3;
|
|
18306
|
+
var MAX_RESTARTS_PER_WINDOW = 3;
|
|
18307
|
+
var WINDOW_MS = 60 * 60 * 1e3;
|
|
18308
|
+
var ServerWatchdog = class {
|
|
18309
|
+
failures = 0;
|
|
18310
|
+
restartsAt = [];
|
|
18311
|
+
/** A different pid is serving now. The failure run belongs to the old
|
|
18312
|
+
* process — a fresh server gets full grace — but the restart cap stays:
|
|
18313
|
+
* watchdog restarts change the pid too, and clearing the cap on every
|
|
18314
|
+
* one would disarm the flap guard entirely. */
|
|
18315
|
+
noteNewInstance() {
|
|
18316
|
+
this.failures = 0;
|
|
18317
|
+
}
|
|
18318
|
+
/** No tracked server at all (pid file gone). Watchdog restarts never pass
|
|
18319
|
+
* through this state — only an operator stop (or a cycle the watchdog
|
|
18320
|
+
* happens to observe mid-gap) does — so a human is at the wheel and the
|
|
18321
|
+
* restart budget re-arms in full. */
|
|
18322
|
+
noteServerGone() {
|
|
18323
|
+
this.failures = 0;
|
|
18324
|
+
this.restartsAt = [];
|
|
18325
|
+
}
|
|
18326
|
+
onProbe(ok, nowMs) {
|
|
18327
|
+
if (ok) {
|
|
18328
|
+
this.failures = 0;
|
|
18329
|
+
return "ok";
|
|
18330
|
+
}
|
|
18331
|
+
this.failures = Math.min(this.failures + 1, FAILURE_THRESHOLD);
|
|
18332
|
+
if (this.failures < FAILURE_THRESHOLD) return "failing";
|
|
18333
|
+
this.restartsAt = this.restartsAt.filter((t) => nowMs - t < WINDOW_MS);
|
|
18334
|
+
if (this.restartsAt.length >= MAX_RESTARTS_PER_WINDOW) return "gave-up";
|
|
18335
|
+
this.restartsAt.push(nowMs);
|
|
18336
|
+
this.failures = 0;
|
|
18337
|
+
return "restart";
|
|
18338
|
+
}
|
|
18339
|
+
};
|
|
18340
|
+
|
|
18059
18341
|
// src/daemon-worker.ts
|
|
18060
18342
|
var USAGE_LOG3 = cclensPath("usage.jsonl");
|
|
18061
18343
|
var DAEMON_LOG = cclensPath("daemon.log");
|
|
18062
18344
|
var UPDATE_STATE = cclensPath("daemon-update.json");
|
|
18063
18345
|
var WATCHDOG_INTERVAL_MS = 5 * 1e3;
|
|
18064
18346
|
var AUTO_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
18065
|
-
|
|
18347
|
+
var SERVER_HEALTH_INTERVAL_MS = 60 * 1e3;
|
|
18348
|
+
var SERVER_HEALTH_TIMEOUT_MS = 10 * 1e3;
|
|
18349
|
+
mkdirSync15(dirname15(USAGE_LOG3), { recursive: true });
|
|
18066
18350
|
function log2(level, message) {
|
|
18067
18351
|
appendDaemonLogLine(level, message);
|
|
18068
18352
|
}
|
|
18069
18353
|
var nextPollAtMs = 0;
|
|
18070
18354
|
var nextAuxPollAtMs = 0;
|
|
18071
18355
|
var nextTeamSyncAtMs = 0;
|
|
18356
|
+
var nextServerHealthAtMs = 0;
|
|
18072
18357
|
var firstTeamSync = true;
|
|
18073
18358
|
var currentIntervalMs = BASE_INTERVAL_MS;
|
|
18074
18359
|
var waitingForRefresh = false;
|
|
@@ -18101,14 +18386,14 @@ var perceptionHandle = setInterval(async () => {
|
|
|
18101
18386
|
}, PERCEPTION_INTERVAL_MS);
|
|
18102
18387
|
function readUpdateState() {
|
|
18103
18388
|
try {
|
|
18104
|
-
return JSON.parse(
|
|
18389
|
+
return JSON.parse(readFileSync23(UPDATE_STATE, "utf8"));
|
|
18105
18390
|
} catch {
|
|
18106
18391
|
return null;
|
|
18107
18392
|
}
|
|
18108
18393
|
}
|
|
18109
18394
|
function writeUpdateState(state) {
|
|
18110
18395
|
try {
|
|
18111
|
-
|
|
18396
|
+
writeFileSync16(UPDATE_STATE, JSON.stringify(state, null, 2), { mode: 384 });
|
|
18112
18397
|
} catch {
|
|
18113
18398
|
}
|
|
18114
18399
|
}
|
|
@@ -18121,7 +18406,7 @@ function nextUpdateCheckFromState(nowMs) {
|
|
|
18121
18406
|
}
|
|
18122
18407
|
var nextUpdateCheckAtMs = nextUpdateCheckFromState(Date.now());
|
|
18123
18408
|
function cliEntryPath() {
|
|
18124
|
-
return
|
|
18409
|
+
return join15(dirname15(fileURLToPath2(import.meta.url)), "index.js");
|
|
18125
18410
|
}
|
|
18126
18411
|
async function runDaemonUpdateCheck() {
|
|
18127
18412
|
if (process.env.FLEETLENS_DAEMON_AUTO_UPDATE === "0") {
|
|
@@ -18153,7 +18438,7 @@ async function runDaemonUpdateCheck() {
|
|
|
18153
18438
|
return;
|
|
18154
18439
|
}
|
|
18155
18440
|
const entry = cliEntryPath();
|
|
18156
|
-
if (!
|
|
18441
|
+
if (!existsSync21(entry)) {
|
|
18157
18442
|
log2("warn", `update check found ${availability.latest}, but CLI entry is missing at ${entry}`);
|
|
18158
18443
|
return;
|
|
18159
18444
|
}
|
|
@@ -18162,7 +18447,7 @@ async function runDaemonUpdateCheck() {
|
|
|
18162
18447
|
logFd = openSync(DAEMON_LOG, "a");
|
|
18163
18448
|
} catch {
|
|
18164
18449
|
}
|
|
18165
|
-
const child =
|
|
18450
|
+
const child = spawn4(process.execPath, [entry, "update"], {
|
|
18166
18451
|
detached: true,
|
|
18167
18452
|
stdio: ["ignore", logFd, logFd],
|
|
18168
18453
|
env: { ...process.env, FLEETLENS_UPDATE_SOURCE: "daemon" }
|
|
@@ -18192,6 +18477,44 @@ async function runDaemonUpdateCheck() {
|
|
|
18192
18477
|
nextUpdateCheckAtMs = Date.now() + AUTO_UPDATE_INTERVAL_MS;
|
|
18193
18478
|
}
|
|
18194
18479
|
}
|
|
18480
|
+
var serverWatchdog = new ServerWatchdog();
|
|
18481
|
+
var lastServerVerdict = "ok";
|
|
18482
|
+
var lastServerPid = null;
|
|
18483
|
+
async function runServerHealthCheck() {
|
|
18484
|
+
const status = getServerStatus();
|
|
18485
|
+
if (!status.running) {
|
|
18486
|
+
if (lastServerPid !== null) {
|
|
18487
|
+
serverWatchdog.noteServerGone();
|
|
18488
|
+
lastServerPid = null;
|
|
18489
|
+
}
|
|
18490
|
+
return;
|
|
18491
|
+
}
|
|
18492
|
+
if (status.pid !== lastServerPid) {
|
|
18493
|
+
serverWatchdog.noteNewInstance();
|
|
18494
|
+
lastServerPid = status.pid;
|
|
18495
|
+
}
|
|
18496
|
+
const ok = await probeServerHealth(status.port, SERVER_HEALTH_TIMEOUT_MS);
|
|
18497
|
+
const verdict = serverWatchdog.onProbe(ok, Date.now());
|
|
18498
|
+
if (verdict === "failing") {
|
|
18499
|
+
log2("warn", `[watchdog] server pid=${status.pid} not answering on port ${status.port}`);
|
|
18500
|
+
} else if (verdict === "restart") {
|
|
18501
|
+
log2("warn", `[watchdog] server pid=${status.pid} wedged; force-restarting on port ${status.port}`);
|
|
18502
|
+
try {
|
|
18503
|
+
const fresh = await restartWedgedServer(status.pid, status.port);
|
|
18504
|
+
log2("info", `[watchdog] server restarted (pid=${fresh.pid}, port=${fresh.port})`);
|
|
18505
|
+
} catch (err) {
|
|
18506
|
+
log2("error", `[watchdog] restart failed: ${err.message}`);
|
|
18507
|
+
}
|
|
18508
|
+
} else if (verdict === "gave-up" && lastServerVerdict !== "gave-up") {
|
|
18509
|
+
log2(
|
|
18510
|
+
"error",
|
|
18511
|
+
`[watchdog] server keeps wedging after 3 restarts within the hour; standing down \u2014 run 'fleetlens start' to restart manually`
|
|
18512
|
+
);
|
|
18513
|
+
} else if (verdict === "ok" && lastServerVerdict !== "ok") {
|
|
18514
|
+
log2("info", `[watchdog] server responding again (pid=${status.pid})`);
|
|
18515
|
+
}
|
|
18516
|
+
lastServerVerdict = verdict;
|
|
18517
|
+
}
|
|
18195
18518
|
async function pollAuxiliaryUsage() {
|
|
18196
18519
|
for (const source of agentSources) {
|
|
18197
18520
|
if (source.kind === "claude-code") continue;
|
|
@@ -18353,6 +18676,10 @@ async function runLoop() {
|
|
|
18353
18676
|
if (Date.now() >= nextUpdateCheckAtMs) {
|
|
18354
18677
|
await runDaemonUpdateCheck();
|
|
18355
18678
|
}
|
|
18679
|
+
if (Date.now() >= nextServerHealthAtMs) {
|
|
18680
|
+
await runServerHealthCheck();
|
|
18681
|
+
nextServerHealthAtMs = Date.now() + SERVER_HEALTH_INTERVAL_MS;
|
|
18682
|
+
}
|
|
18356
18683
|
await sleep2(WATCHDOG_INTERVAL_MS);
|
|
18357
18684
|
}
|
|
18358
18685
|
}
|