@swestash/agent-lens 0.9.6 → 0.10.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/dist/agent-lens.js +215 -90
- package/dist/agent-lens.js.map +1 -1
- package/package.json +1 -1
- package/web/404.html +2 -2
- package/web/assets/AboutView-Bngkx739.js +1 -0
- package/web/assets/{Dashboard-BkRLAY2N.js → Dashboard-B9-O6UM7.js} +1 -1
- package/web/assets/{FileView-BbPK6hx9.js → FileView-D4iZxHta.js} +1 -1
- package/web/assets/{FilesView-D0gm4_XO.js → FilesView-bjBm-f1c.js} +1 -1
- package/web/assets/{SecurityView-92YGEb3-.js → SecurityView-DNgbLbZ2.js} +1 -1
- package/web/assets/{SessionView-Dy0ELjaS.js → SessionView-BCz9AnOz.js} +1 -1
- package/web/assets/{SkillView-Te5jcVBw.js → SkillView-D6egSywk.js} +1 -1
- package/web/assets/{SkillsView-FtrADGqR.js → SkillsView-Dvke2ty1.js} +1 -1
- package/web/assets/{WorkflowView-D45UzOuV.js → WorkflowView-BadGoeGI.js} +1 -1
- package/web/assets/index-CeW4iDDs.css +1 -0
- package/web/assets/{index-DYY0_SmQ.js → index-CqWARNqS.js} +13 -13
- package/web/assets/{index-Bgxu3c84.js → index-DxkiGVr3.js} +1 -1
- package/web/assets/{jsonish-Dd3X-MG6.js → jsonish-SimOVe9L.js} +1 -1
- package/web/assets/{severity-CoO1IKlD.js → severity-DJTsjBgl.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-DBaa9asK.css +0 -1
package/dist/agent-lens.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { existsSync as existsSync10,
|
|
5
|
-
import {
|
|
6
|
-
import { fileURLToPath as
|
|
4
|
+
import { existsSync as existsSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
5
|
+
import { join as join12 } from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7
7
|
|
|
8
8
|
// ../../node_modules/.pnpm/cac@6.7.14/node_modules/cac/dist/index.mjs
|
|
9
9
|
import { EventEmitter } from "events";
|
|
@@ -107,7 +107,7 @@ var findAllBrackets = (v) => {
|
|
|
107
107
|
const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
|
|
108
108
|
const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
|
|
109
109
|
const res = [];
|
|
110
|
-
const
|
|
110
|
+
const parse2 = (match) => {
|
|
111
111
|
let variadic = false;
|
|
112
112
|
let value = match[1];
|
|
113
113
|
if (value.startsWith("...")) {
|
|
@@ -122,11 +122,11 @@ var findAllBrackets = (v) => {
|
|
|
122
122
|
};
|
|
123
123
|
let angledMatch;
|
|
124
124
|
while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
|
|
125
|
-
res.push(
|
|
125
|
+
res.push(parse2(angledMatch));
|
|
126
126
|
}
|
|
127
127
|
let squareMatch;
|
|
128
128
|
while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
|
|
129
|
-
res.push(
|
|
129
|
+
res.push(parse2(squareMatch));
|
|
130
130
|
}
|
|
131
131
|
return res;
|
|
132
132
|
};
|
|
@@ -1377,6 +1377,12 @@ import { join as join2 } from "path";
|
|
|
1377
1377
|
var DEFAULT_PORT = 4477;
|
|
1378
1378
|
var DEFAULT_HOST = "127.0.0.1";
|
|
1379
1379
|
var DEFAULT_DB_NAME = "agent-lens.db";
|
|
1380
|
+
var DEFAULT_VERSIONS_KEEP_DAYS = 90;
|
|
1381
|
+
function resolveRetention() {
|
|
1382
|
+
const raw = process.env.AGENT_LENS_VERSIONS_KEEP_DAYS;
|
|
1383
|
+
const parsed = raw ? Number(raw) : NaN;
|
|
1384
|
+
return Number.isFinite(parsed) && parsed >= 0 ? { keepDays: parsed, origin: "env" } : { keepDays: DEFAULT_VERSIONS_KEEP_DAYS, origin: "default" };
|
|
1385
|
+
}
|
|
1380
1386
|
function readConfigFile() {
|
|
1381
1387
|
const repoRoot = findRepoRoot();
|
|
1382
1388
|
const dataDir = resolveDataDir(repoRoot);
|
|
@@ -1436,6 +1442,59 @@ function resolveServerConfig(overrides = {}, cfg = readConfigFile()) {
|
|
|
1436
1442
|
return { port, host, portOrigin, hostOrigin };
|
|
1437
1443
|
}
|
|
1438
1444
|
|
|
1445
|
+
// ../core/dist/version.js
|
|
1446
|
+
import { spawnSync } from "child_process";
|
|
1447
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1448
|
+
import { dirname as dirname2, join as join3, parse } from "path";
|
|
1449
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1450
|
+
var moduleDir2 = dirname2(fileURLToPath2(import.meta.url));
|
|
1451
|
+
function isPlaceholder(v) {
|
|
1452
|
+
return v.startsWith("0.0.0");
|
|
1453
|
+
}
|
|
1454
|
+
function nearestPackageVersion(dir) {
|
|
1455
|
+
const { root } = parse(dir);
|
|
1456
|
+
for (let d = dir; ; d = dirname2(d)) {
|
|
1457
|
+
try {
|
|
1458
|
+
const pkg = JSON.parse(readFileSync3(join3(d, "package.json"), "utf8"));
|
|
1459
|
+
if (typeof pkg.version === "string" && pkg.version)
|
|
1460
|
+
return pkg.version;
|
|
1461
|
+
} catch {
|
|
1462
|
+
}
|
|
1463
|
+
if (d === root)
|
|
1464
|
+
return null;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function gitDescribe(cwd) {
|
|
1468
|
+
try {
|
|
1469
|
+
const r = spawnSync("git", ["describe", "--tags", "--always", "--dirty"], {
|
|
1470
|
+
cwd,
|
|
1471
|
+
encoding: "utf8",
|
|
1472
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1473
|
+
});
|
|
1474
|
+
if (r.status !== 0)
|
|
1475
|
+
return null;
|
|
1476
|
+
const out = r.stdout?.trim();
|
|
1477
|
+
return out ? out : null;
|
|
1478
|
+
} catch {
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
function computeVersion(fromDir = moduleDir2) {
|
|
1483
|
+
const pkg = nearestPackageVersion(fromDir);
|
|
1484
|
+
if (pkg && !isPlaceholder(pkg))
|
|
1485
|
+
return { version: pkg, source: "npm" };
|
|
1486
|
+
const described = gitDescribe(fromDir);
|
|
1487
|
+
if (described)
|
|
1488
|
+
return { version: described, source: "git" };
|
|
1489
|
+
return { version: "unknown", source: "unknown" };
|
|
1490
|
+
}
|
|
1491
|
+
var cached = null;
|
|
1492
|
+
function resolveVersion() {
|
|
1493
|
+
if (!cached)
|
|
1494
|
+
cached = computeVersion();
|
|
1495
|
+
return cached;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1439
1498
|
// ../core/dist/sources.js
|
|
1440
1499
|
function loadSources() {
|
|
1441
1500
|
if (process.env.CLAUDE_DIR) {
|
|
@@ -1490,7 +1549,7 @@ function encodeProjectPath(p) {
|
|
|
1490
1549
|
|
|
1491
1550
|
// ../core/dist/collect.js
|
|
1492
1551
|
import { appendFileSync, closeSync, copyFileSync, existsSync as existsSync2, mkdirSync, openSync, readSync, readdirSync, statSync, unlinkSync, utimesSync, writeSync, chmodSync } from "fs";
|
|
1493
|
-
import { basename, dirname as
|
|
1552
|
+
import { basename, dirname as dirname3, join as join4, relative, sep } from "path";
|
|
1494
1553
|
import { platform as platform2 } from "os";
|
|
1495
1554
|
var POSIX = platform2() !== "win32";
|
|
1496
1555
|
var DIR_MODE = 448;
|
|
@@ -1516,7 +1575,7 @@ function syncMeta(dst, src) {
|
|
|
1516
1575
|
}
|
|
1517
1576
|
}
|
|
1518
1577
|
function copyWhole(src, dst, srcStat) {
|
|
1519
|
-
ensureDir(
|
|
1578
|
+
ensureDir(dirname3(dst));
|
|
1520
1579
|
copyFileSync(src, dst);
|
|
1521
1580
|
syncMeta(dst, srcStat);
|
|
1522
1581
|
}
|
|
@@ -1570,27 +1629,27 @@ function filesEqual(a, b) {
|
|
|
1570
1629
|
return prefixEquals(a, b, sa.size);
|
|
1571
1630
|
}
|
|
1572
1631
|
function latestSnapshot(archive, relParts) {
|
|
1573
|
-
const versRoot =
|
|
1632
|
+
const versRoot = join4(archive, ".versions");
|
|
1574
1633
|
if (!existsSync2(versRoot))
|
|
1575
1634
|
return null;
|
|
1576
1635
|
const stamps = readdirSync(versRoot).sort();
|
|
1577
1636
|
for (let i = stamps.length - 1; i >= 0; i--) {
|
|
1578
|
-
const p =
|
|
1637
|
+
const p = join4(versRoot, stamps[i], ...relParts);
|
|
1579
1638
|
if (existsSync2(p))
|
|
1580
1639
|
return p;
|
|
1581
1640
|
}
|
|
1582
1641
|
return null;
|
|
1583
1642
|
}
|
|
1584
1643
|
function snapshot(absPath, relParts, versionsDir, stats) {
|
|
1585
|
-
const dst =
|
|
1586
|
-
ensureDir(
|
|
1644
|
+
const dst = join4(versionsDir, ...relParts);
|
|
1645
|
+
ensureDir(dirname3(dst));
|
|
1587
1646
|
copyFileSync(absPath, dst);
|
|
1588
1647
|
syncMeta(dst, statSync(absPath));
|
|
1589
1648
|
stats.snapshots++;
|
|
1590
1649
|
}
|
|
1591
1650
|
function walkCollectable(dir, out, inWorkflows = false, inToolResults = false) {
|
|
1592
1651
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
1593
|
-
const p =
|
|
1652
|
+
const p = join4(dir, e.name);
|
|
1594
1653
|
if (e.isDirectory()) {
|
|
1595
1654
|
walkCollectable(p, out, inWorkflows || e.name === "workflows", inToolResults || e.name === "tool-results");
|
|
1596
1655
|
} else if (e.isFile() && (e.name.endsWith(".jsonl") || inWorkflows || inToolResults || e.name.endsWith(".meta.json"))) {
|
|
@@ -1631,7 +1690,7 @@ function removeCredentials(dir) {
|
|
|
1631
1690
|
if (!existsSync2(dir))
|
|
1632
1691
|
return;
|
|
1633
1692
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
1634
|
-
const p =
|
|
1693
|
+
const p = join4(dir, e.name);
|
|
1635
1694
|
if (e.isDirectory())
|
|
1636
1695
|
removeCredentials(p);
|
|
1637
1696
|
else if (e.name === ".credentials.json") {
|
|
@@ -1644,19 +1703,19 @@ function removeCredentials(dir) {
|
|
|
1644
1703
|
}
|
|
1645
1704
|
function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
1646
1705
|
const { label, configDir } = source;
|
|
1647
|
-
const archive =
|
|
1648
|
-
const versionsDir =
|
|
1706
|
+
const archive = join4(archiveBase, label);
|
|
1707
|
+
const versionsDir = join4(archive, ".versions", runTs);
|
|
1649
1708
|
if (!existsSync2(configDir)) {
|
|
1650
1709
|
log(`agent-lens: [${label}] source not found: ${configDir} (skipping)`);
|
|
1651
1710
|
return;
|
|
1652
1711
|
}
|
|
1653
|
-
ensureDir(
|
|
1654
|
-
ensureDir(
|
|
1712
|
+
ensureDir(join4(archive, "projects"));
|
|
1713
|
+
ensureDir(join4(archive, "settings"));
|
|
1655
1714
|
const files = [];
|
|
1656
|
-
const projectsDir =
|
|
1715
|
+
const projectsDir = join4(configDir, "projects");
|
|
1657
1716
|
if (existsSync2(projectsDir))
|
|
1658
1717
|
walkCollectable(projectsDir, files);
|
|
1659
|
-
const historySrc =
|
|
1718
|
+
const historySrc = join4(configDir, "history.jsonl");
|
|
1660
1719
|
if (existsSync2(historySrc))
|
|
1661
1720
|
files.push(historySrc);
|
|
1662
1721
|
const before = { scanned: stats.scanned, snapshots: stats.snapshots };
|
|
@@ -1669,16 +1728,16 @@ function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
|
1669
1728
|
if (excludedDirs.some((enc) => relPosix.startsWith(`projects/${enc}/`)))
|
|
1670
1729
|
continue;
|
|
1671
1730
|
stats.scanned++;
|
|
1672
|
-
syncFile(src,
|
|
1731
|
+
syncFile(src, join4(archive, ...relParts), relParts, archive, versionsDir, stats, base.endsWith(".jsonl"));
|
|
1673
1732
|
}
|
|
1674
1733
|
for (const f of ["settings.json", "settings.local.json"]) {
|
|
1675
|
-
const s =
|
|
1734
|
+
const s = join4(configDir, f);
|
|
1676
1735
|
if (!existsSync2(s))
|
|
1677
1736
|
continue;
|
|
1678
|
-
const a =
|
|
1737
|
+
const a = join4(archive, "settings", f);
|
|
1679
1738
|
if (existsSync2(a) && !filesEqual(s, a))
|
|
1680
1739
|
snapshot(a, ["settings", f], versionsDir, stats);
|
|
1681
|
-
ensureDir(
|
|
1740
|
+
ensureDir(dirname3(a));
|
|
1682
1741
|
copyFileSync(s, a);
|
|
1683
1742
|
syncMeta(a, statSync(s));
|
|
1684
1743
|
}
|
|
@@ -1688,7 +1747,7 @@ function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
|
1688
1747
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} run=${runTs} source=${label} scanned=${scanned} snapshots=${snapshots} archive=${archive}`;
|
|
1689
1748
|
log(`agent-lens: ${line}`);
|
|
1690
1749
|
try {
|
|
1691
|
-
appendFileSync(
|
|
1750
|
+
appendFileSync(join4(archiveBase, ".collect.log"), line + "\n");
|
|
1692
1751
|
} catch {
|
|
1693
1752
|
}
|
|
1694
1753
|
}
|
|
@@ -1710,8 +1769,8 @@ function collectAll(opts = {}) {
|
|
|
1710
1769
|
}
|
|
1711
1770
|
|
|
1712
1771
|
// ../core/dist/lock.js
|
|
1713
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as
|
|
1714
|
-
import { dirname as
|
|
1772
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync } from "fs";
|
|
1773
|
+
import { dirname as dirname4 } from "path";
|
|
1715
1774
|
import { hostname } from "os";
|
|
1716
1775
|
function isAlive(pid) {
|
|
1717
1776
|
if (!pid)
|
|
@@ -1724,10 +1783,10 @@ function isAlive(pid) {
|
|
|
1724
1783
|
}
|
|
1725
1784
|
}
|
|
1726
1785
|
function acquireLock(lockPath, staleMs = 6 * 60 * 60 * 1e3) {
|
|
1727
|
-
mkdirSync2(
|
|
1786
|
+
mkdirSync2(dirname4(lockPath), { recursive: true });
|
|
1728
1787
|
if (existsSync3(lockPath)) {
|
|
1729
1788
|
try {
|
|
1730
|
-
const held = JSON.parse(
|
|
1789
|
+
const held = JSON.parse(readFileSync4(lockPath, "utf8"));
|
|
1731
1790
|
const fresh = typeof held.ts === "number" && Date.now() - held.ts < staleMs;
|
|
1732
1791
|
if (fresh && isAlive(held.pid ?? 0))
|
|
1733
1792
|
return null;
|
|
@@ -1741,7 +1800,7 @@ function acquireLock(lockPath, staleMs = 6 * 60 * 60 * 1e3) {
|
|
|
1741
1800
|
return;
|
|
1742
1801
|
released = true;
|
|
1743
1802
|
try {
|
|
1744
|
-
const cur = JSON.parse(
|
|
1803
|
+
const cur = JSON.parse(readFileSync4(lockPath, "utf8"));
|
|
1745
1804
|
if (cur.pid === process.pid)
|
|
1746
1805
|
unlinkSync2(lockPath);
|
|
1747
1806
|
} catch {
|
|
@@ -1752,10 +1811,10 @@ function acquireLock(lockPath, staleMs = 6 * 60 * 60 * 1e3) {
|
|
|
1752
1811
|
}
|
|
1753
1812
|
|
|
1754
1813
|
// ../core/dist/service.js
|
|
1755
|
-
import { spawnSync } from "child_process";
|
|
1814
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
1756
1815
|
import { mkdirSync as mkdirSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1757
1816
|
import { homedir as homedir2, platform as platform3, userInfo } from "os";
|
|
1758
|
-
import { join as
|
|
1817
|
+
import { join as join5 } from "path";
|
|
1759
1818
|
var DEFAULT_HOURS = [9, 13, 17, 21];
|
|
1760
1819
|
function currentUser() {
|
|
1761
1820
|
try {
|
|
@@ -1897,15 +1956,15 @@ ${envDict} <key>RunAtLoad</key><true/>
|
|
|
1897
1956
|
`;
|
|
1898
1957
|
}
|
|
1899
1958
|
function sh(cmd, args, quiet = false) {
|
|
1900
|
-
const r =
|
|
1959
|
+
const r = spawnSync2(cmd, args, { stdio: quiet ? "ignore" : "inherit", encoding: "utf8" });
|
|
1901
1960
|
return r.status === 0;
|
|
1902
1961
|
}
|
|
1903
1962
|
function have(cmd) {
|
|
1904
|
-
const r =
|
|
1963
|
+
const r = spawnSync2(cmd, ["--version"], { stdio: "ignore" });
|
|
1905
1964
|
return r.status === 0 || r.error === void 0;
|
|
1906
1965
|
}
|
|
1907
1966
|
function systemdUnitDir() {
|
|
1908
|
-
return
|
|
1967
|
+
return join5(process.env.XDG_CONFIG_HOME || join5(homedir2(), ".config"), "systemd", "user");
|
|
1909
1968
|
}
|
|
1910
1969
|
function linuxInstall(targets, node, cli2, hours) {
|
|
1911
1970
|
if (!have("systemctl")) {
|
|
@@ -1916,11 +1975,11 @@ function linuxInstall(targets, node, cli2, hours) {
|
|
|
1916
1975
|
const dir = systemdUnitDir();
|
|
1917
1976
|
mkdirSync3(dir, { recursive: true });
|
|
1918
1977
|
if (targets.includes("collector")) {
|
|
1919
|
-
writeFileSync2(
|
|
1920
|
-
writeFileSync2(
|
|
1978
|
+
writeFileSync2(join5(dir, SYSTEMD_COLLECTOR_SERVICE), systemdCollectorService(node, cli2));
|
|
1979
|
+
writeFileSync2(join5(dir, SYSTEMD_COLLECTOR_TIMER), systemdCollectorTimer(hours));
|
|
1921
1980
|
}
|
|
1922
1981
|
if (targets.includes("server")) {
|
|
1923
|
-
writeFileSync2(
|
|
1982
|
+
writeFileSync2(join5(dir, SYSTEMD_SERVER_SERVICE), systemdServerService(node, cli2, serverEnv()));
|
|
1924
1983
|
}
|
|
1925
1984
|
sh("systemctl", ["--user", "daemon-reload"]);
|
|
1926
1985
|
if (targets.includes("collector")) {
|
|
@@ -1945,12 +2004,12 @@ function linuxUninstall(targets) {
|
|
|
1945
2004
|
if (targets.includes("collector")) {
|
|
1946
2005
|
sh("systemctl", ["--user", "disable", "--now", SYSTEMD_COLLECTOR_TIMER], true);
|
|
1947
2006
|
for (const u of [SYSTEMD_COLLECTOR_TIMER, SYSTEMD_COLLECTOR_SERVICE])
|
|
1948
|
-
rmSync(
|
|
2007
|
+
rmSync(join5(dir, u), { force: true });
|
|
1949
2008
|
sh("systemctl", ["--user", "reset-failed", SYSTEMD_COLLECTOR_SERVICE], true);
|
|
1950
2009
|
}
|
|
1951
2010
|
if (targets.includes("server")) {
|
|
1952
2011
|
sh("systemctl", ["--user", "disable", "--now", SYSTEMD_SERVER_SERVICE], true);
|
|
1953
|
-
rmSync(
|
|
2012
|
+
rmSync(join5(dir, SYSTEMD_SERVER_SERVICE), { force: true });
|
|
1954
2013
|
sh("systemctl", ["--user", "reset-failed", SYSTEMD_SERVER_SERVICE], true);
|
|
1955
2014
|
}
|
|
1956
2015
|
sh("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -1965,7 +2024,7 @@ function linuxStatus(targets) {
|
|
|
1965
2024
|
sh("systemctl", ["--user", "status", SYSTEMD_SERVER_SERVICE, "--no-pager"]);
|
|
1966
2025
|
}
|
|
1967
2026
|
function launchdPlistPath(label) {
|
|
1968
|
-
return
|
|
2027
|
+
return join5(homedir2(), "Library", "LaunchAgents", `${label}.plist`);
|
|
1969
2028
|
}
|
|
1970
2029
|
function macBootstrap(plist) {
|
|
1971
2030
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
@@ -1979,18 +2038,18 @@ function macBootout(label, plist) {
|
|
|
1979
2038
|
rmSync(plist, { force: true });
|
|
1980
2039
|
}
|
|
1981
2040
|
function macInstall(targets, node, cli2, hours) {
|
|
1982
|
-
const agents =
|
|
2041
|
+
const agents = join5(homedir2(), "Library", "LaunchAgents");
|
|
1983
2042
|
mkdirSync3(agents, { recursive: true });
|
|
1984
2043
|
const dataDir = resolveDataDir(findRepoRoot());
|
|
1985
2044
|
if (targets.includes("collector")) {
|
|
1986
2045
|
const plist = launchdPlistPath(LAUNCHD_COLLECTOR_LABEL);
|
|
1987
|
-
writeFileSync2(plist, launchdCollectorPlist(node, cli2, hours,
|
|
2046
|
+
writeFileSync2(plist, launchdCollectorPlist(node, cli2, hours, join5(dataDir, "schedule.log")));
|
|
1988
2047
|
macBootstrap(plist);
|
|
1989
2048
|
console.log(`agent-lens service: installed collector agent ${LAUNCHD_COLLECTOR_LABEL} (hours ${hours.join(",")})`);
|
|
1990
2049
|
}
|
|
1991
2050
|
if (targets.includes("server")) {
|
|
1992
2051
|
const plist = launchdPlistPath(LAUNCHD_SERVER_LABEL);
|
|
1993
|
-
writeFileSync2(plist, launchdServerPlist(node, cli2,
|
|
2052
|
+
writeFileSync2(plist, launchdServerPlist(node, cli2, join5(dataDir, "server.log"), serverEnv()));
|
|
1994
2053
|
macBootstrap(plist);
|
|
1995
2054
|
console.log(`agent-lens service: installed server agent ${LAUNCHD_SERVER_LABEL}`);
|
|
1996
2055
|
}
|
|
@@ -2080,8 +2139,8 @@ function runService(action, params) {
|
|
|
2080
2139
|
}
|
|
2081
2140
|
|
|
2082
2141
|
// ../ingest/dist/run.js
|
|
2083
|
-
import { readFileSync as
|
|
2084
|
-
import { dirname as
|
|
2142
|
+
import { readFileSync as readFileSync6, statSync as statSync3, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
2143
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
2085
2144
|
|
|
2086
2145
|
// ../ingest/dist/db.js
|
|
2087
2146
|
import Database from "better-sqlite3";
|
|
@@ -2138,7 +2197,7 @@ function resetSchema(db) {
|
|
|
2138
2197
|
|
|
2139
2198
|
// ../ingest/dist/adapters/claude-code.js
|
|
2140
2199
|
import { readdirSync as readdirSync2 } from "fs";
|
|
2141
|
-
import { basename as basename2, join as
|
|
2200
|
+
import { basename as basename2, join as join6 } from "path";
|
|
2142
2201
|
function flattenText(content) {
|
|
2143
2202
|
if (content == null)
|
|
2144
2203
|
return null;
|
|
@@ -2221,7 +2280,7 @@ function recurseJsonl(dir, out) {
|
|
|
2221
2280
|
return;
|
|
2222
2281
|
}
|
|
2223
2282
|
for (const e of entries) {
|
|
2224
|
-
const p =
|
|
2283
|
+
const p = join6(dir, e.name);
|
|
2225
2284
|
if (e.isDirectory())
|
|
2226
2285
|
recurseJsonl(p, out);
|
|
2227
2286
|
else if (e.isFile() && e.name.endsWith(".jsonl"))
|
|
@@ -2252,12 +2311,12 @@ var ClaudeCodeAdapter = class {
|
|
|
2252
2311
|
});
|
|
2253
2312
|
}
|
|
2254
2313
|
};
|
|
2255
|
-
addFrom(
|
|
2256
|
-
const versionsRoot =
|
|
2314
|
+
addFrom(join6(archiveRoot, "projects"), false);
|
|
2315
|
+
const versionsRoot = join6(archiveRoot, ".versions");
|
|
2257
2316
|
try {
|
|
2258
2317
|
for (const ts of readdirSync2(versionsRoot, { withFileTypes: true })) {
|
|
2259
2318
|
if (ts.isDirectory())
|
|
2260
|
-
addFrom(
|
|
2319
|
+
addFrom(join6(versionsRoot, ts.name, "projects"), true);
|
|
2261
2320
|
}
|
|
2262
2321
|
} catch {
|
|
2263
2322
|
}
|
|
@@ -3311,7 +3370,7 @@ function deriveFileChanges(db, dirty) {
|
|
|
3311
3370
|
import { existsSync as existsSync4 } from "fs";
|
|
3312
3371
|
import { homedir as homedir3 } from "os";
|
|
3313
3372
|
import { createHash as createHash4 } from "crypto";
|
|
3314
|
-
import { dirname as
|
|
3373
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
3315
3374
|
function projectId(agentId, path3) {
|
|
3316
3375
|
return createHash4("sha1").update(`${agentId}\0${path3}`).digest("hex").slice(0, 16);
|
|
3317
3376
|
}
|
|
@@ -3319,9 +3378,9 @@ var strip = (p) => p.length > 1 ? p.replace(/\/$/, "") : p;
|
|
|
3319
3378
|
function nearestGitRoot(path3, home) {
|
|
3320
3379
|
let cur = strip(path3);
|
|
3321
3380
|
while (cur !== home && cur !== "/" && cur.length > 0) {
|
|
3322
|
-
if (existsSync4(
|
|
3381
|
+
if (existsSync4(join7(cur, ".git")))
|
|
3323
3382
|
return cur;
|
|
3324
|
-
const next =
|
|
3383
|
+
const next = dirname5(cur);
|
|
3325
3384
|
if (next === cur)
|
|
3326
3385
|
break;
|
|
3327
3386
|
cur = next;
|
|
@@ -3348,12 +3407,12 @@ function canonicalizeProjects(db, opts = {}) {
|
|
|
3348
3407
|
if (git) {
|
|
3349
3408
|
out = git;
|
|
3350
3409
|
} else if (existsSync4(p) || !withMains.has(byPath.get(p)?.id ?? "")) {
|
|
3351
|
-
for (let cur =
|
|
3410
|
+
for (let cur = dirname5(p); cur !== "/" && cur !== home && cur.length > 0; cur = dirname5(cur)) {
|
|
3352
3411
|
if (byPath.has(cur)) {
|
|
3353
3412
|
out = canon(cur);
|
|
3354
3413
|
break;
|
|
3355
3414
|
}
|
|
3356
|
-
if (
|
|
3415
|
+
if (dirname5(cur) === cur)
|
|
3357
3416
|
break;
|
|
3358
3417
|
}
|
|
3359
3418
|
}
|
|
@@ -3861,8 +3920,8 @@ function ingestFile(db, stmts, adapter, file, lines, meta, now2, stats) {
|
|
|
3861
3920
|
import { basename as basename3 } from "path";
|
|
3862
3921
|
|
|
3863
3922
|
// ../ingest/dist/sidecar.js
|
|
3864
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
3865
|
-
import { join as
|
|
3923
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
3924
|
+
import { join as join8 } from "path";
|
|
3866
3925
|
|
|
3867
3926
|
// ../ingest/dist/redact.js
|
|
3868
3927
|
import { createHash as createHash6, randomBytes } from "crypto";
|
|
@@ -3937,7 +3996,7 @@ function walk(dir, subdir, inSubdir, matchName, out) {
|
|
|
3937
3996
|
return;
|
|
3938
3997
|
}
|
|
3939
3998
|
for (const e of entries) {
|
|
3940
|
-
const p =
|
|
3999
|
+
const p = join8(dir, e.name);
|
|
3941
4000
|
if (e.isDirectory())
|
|
3942
4001
|
walk(p, subdir, inSubdir || e.name === subdir, matchName, out);
|
|
3943
4002
|
else if (e.isFile() && inSubdir && matchName(e.name))
|
|
@@ -3946,11 +4005,11 @@ function walk(dir, subdir, inSubdir, matchName, out) {
|
|
|
3946
4005
|
}
|
|
3947
4006
|
function discover(sourceArchiveDir, subdir, matchName) {
|
|
3948
4007
|
const out = [];
|
|
3949
|
-
walk(
|
|
4008
|
+
walk(join8(sourceArchiveDir, "projects"), subdir, false, matchName, out);
|
|
3950
4009
|
try {
|
|
3951
|
-
for (const ts of readdirSync3(
|
|
4010
|
+
for (const ts of readdirSync3(join8(sourceArchiveDir, ".versions"), { withFileTypes: true }))
|
|
3952
4011
|
if (ts.isDirectory())
|
|
3953
|
-
walk(
|
|
4012
|
+
walk(join8(sourceArchiveDir, ts.name, "projects"), subdir, false, matchName, out);
|
|
3954
4013
|
} catch {
|
|
3955
4014
|
}
|
|
3956
4015
|
return out;
|
|
@@ -3977,7 +4036,7 @@ function ingestSidecars(db, sourceArchiveDir, excludedDirs, now2, stats, full, c
|
|
|
3977
4036
|
}
|
|
3978
4037
|
let buf;
|
|
3979
4038
|
try {
|
|
3980
|
-
buf =
|
|
4039
|
+
buf = readFileSync5(path3);
|
|
3981
4040
|
} catch {
|
|
3982
4041
|
stats.malformed++;
|
|
3983
4042
|
continue;
|
|
@@ -4161,7 +4220,7 @@ function shouldReingest(path3, size, mtimeMs, prev) {
|
|
|
4161
4220
|
if (prev && prev.size === size && prev.mtime_ms === mtimeMs)
|
|
4162
4221
|
return { action: "skip-stat" };
|
|
4163
4222
|
const small = size <= STREAM_THRESHOLD;
|
|
4164
|
-
const buf = small ?
|
|
4223
|
+
const buf = small ? readFileSync6(path3) : null;
|
|
4165
4224
|
const hash2 = small ? sha256(buf) : sha256File(path3);
|
|
4166
4225
|
if (prev && prev.sha256 === hash2)
|
|
4167
4226
|
return { action: "skip-hash", hash: hash2 };
|
|
@@ -4204,7 +4263,7 @@ function runIngest(argv = process.argv.slice(2)) {
|
|
|
4204
4263
|
console.error(`agent-lens-ingest: archive not found: ${archiveRoot} (run 'agent-lens collect' first)`);
|
|
4205
4264
|
process.exit(1);
|
|
4206
4265
|
}
|
|
4207
|
-
mkdirSync4(
|
|
4266
|
+
mkdirSync4(dirname6(dbPath), { recursive: true });
|
|
4208
4267
|
const db = args.full ? openRaw(dbPath) : openDb(dbPath);
|
|
4209
4268
|
if (args.full) {
|
|
4210
4269
|
resetSchema(db);
|
|
@@ -4237,7 +4296,7 @@ function runIngest(argv = process.argv.slice(2)) {
|
|
|
4237
4296
|
}
|
|
4238
4297
|
stmts.insAgent.run(adapter.agentId, adapter.agentName);
|
|
4239
4298
|
stmts.insSource.run({ id: source.label, label: source.label, agent_id: adapter.agentId, config_dir: source.configDir });
|
|
4240
|
-
let files = adapter.discover(
|
|
4299
|
+
let files = adapter.discover(join9(archiveRoot, source.label), source.label);
|
|
4241
4300
|
if (excludedDirs.length)
|
|
4242
4301
|
files = files.filter((f) => !isExcludedArchivePath(f.path, excludedDirs));
|
|
4243
4302
|
files.sort((a, b) => Number(a.isVersion) - Number(b.isVersion));
|
|
@@ -4267,9 +4326,9 @@ function runIngest(argv = process.argv.slice(2)) {
|
|
|
4267
4326
|
ingestFile(db, stmts, adapter, file, lines, { size: st.size, mtimeMs, hash: decision.hash }, now2, stats);
|
|
4268
4327
|
dirty.add(file.sessionId);
|
|
4269
4328
|
}
|
|
4270
|
-
ingestWorkflowResults(db,
|
|
4271
|
-
ingestSubagentMeta(db,
|
|
4272
|
-
ingestToolResults(db,
|
|
4329
|
+
ingestWorkflowResults(db, join9(archiveRoot, source.label), source.label, excludedDirs, now2, wfStats, args.full);
|
|
4330
|
+
ingestSubagentMeta(db, join9(archiveRoot, source.label), source.label, excludedDirs, now2, metaStats, args.full);
|
|
4331
|
+
ingestToolResults(db, join9(archiveRoot, source.label), excludedDirs, now2, trStats, args.full);
|
|
4273
4332
|
}
|
|
4274
4333
|
const expanded = rebuildDerived(db, args.full ? null : dirty);
|
|
4275
4334
|
canonicalizeProjects(db);
|
|
@@ -4301,8 +4360,8 @@ function runMetrics(argv = process.argv.slice(2)) {
|
|
|
4301
4360
|
|
|
4302
4361
|
// ../server/dist/run.js
|
|
4303
4362
|
import { existsSync as existsSync8 } from "fs";
|
|
4304
|
-
import { dirname as
|
|
4305
|
-
import { fileURLToPath as
|
|
4363
|
+
import { dirname as dirname7 } from "path";
|
|
4364
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4306
4365
|
|
|
4307
4366
|
// ../server/dist/db.js
|
|
4308
4367
|
import Database2 from "better-sqlite3";
|
|
@@ -5384,7 +5443,7 @@ function dashboardBreakdowns(db, f) {
|
|
|
5384
5443
|
|
|
5385
5444
|
// ../server/dist/refresh.js
|
|
5386
5445
|
import { existsSync as existsSync6, mkdirSync as mkdirSync5 } from "fs";
|
|
5387
|
-
import { join as
|
|
5446
|
+
import { join as join10 } from "path";
|
|
5388
5447
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
5389
5448
|
function originAllowed(origin) {
|
|
5390
5449
|
if (!origin)
|
|
@@ -5405,7 +5464,7 @@ function writeBlocked(headers) {
|
|
|
5405
5464
|
}
|
|
5406
5465
|
function runRefresh() {
|
|
5407
5466
|
const dataDir = resolveDataDir(findRepoRoot());
|
|
5408
|
-
const lock = acquireLock(
|
|
5467
|
+
const lock = acquireLock(join10(dataDir, ".agent-lens.lock"));
|
|
5409
5468
|
if (!lock)
|
|
5410
5469
|
return null;
|
|
5411
5470
|
try {
|
|
@@ -5487,6 +5546,61 @@ function listMutes(db) {
|
|
|
5487
5546
|
return db.prepare("SELECT rule_id, scope, scope_id, note, muted_at FROM muted_rules ORDER BY muted_at DESC").all();
|
|
5488
5547
|
}
|
|
5489
5548
|
|
|
5549
|
+
// ../server/dist/about.js
|
|
5550
|
+
import { statSync as statSync4 } from "fs";
|
|
5551
|
+
function storage(db, dbPath) {
|
|
5552
|
+
const row = tableExists(db, "ingest_state") ? queryGet(db, "SELECT COUNT(*) files, SUM(size) bytes, MAX(ingested_at) last FROM ingest_state") : void 0;
|
|
5553
|
+
let db_bytes = null;
|
|
5554
|
+
try {
|
|
5555
|
+
db_bytes = statSync4(dbPath).size;
|
|
5556
|
+
} catch {
|
|
5557
|
+
db_bytes = null;
|
|
5558
|
+
}
|
|
5559
|
+
return {
|
|
5560
|
+
db_bytes,
|
|
5561
|
+
archive_bytes: row?.bytes ?? 0,
|
|
5562
|
+
// SUM over zero rows is NULL, not 0
|
|
5563
|
+
archive_files: row?.files ?? 0,
|
|
5564
|
+
last_ingested: row?.last ?? null
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
function engineVersion(db, table, sql, expected) {
|
|
5568
|
+
const in_data = tableExists(db, table) ? queryAll(db, sql).map((r) => r.v).filter((v) => Number.isFinite(v)) : [];
|
|
5569
|
+
return { expected, in_data, stale: in_data.some((v) => v < expected) };
|
|
5570
|
+
}
|
|
5571
|
+
function about(db, ctx) {
|
|
5572
|
+
const version2 = resolveVersion();
|
|
5573
|
+
const schema = schemaStatus(db);
|
|
5574
|
+
const dataDir = resolveDataDir(ctx.repoRoot);
|
|
5575
|
+
const retention = resolveRetention();
|
|
5576
|
+
return {
|
|
5577
|
+
versions: {
|
|
5578
|
+
app: version2.version,
|
|
5579
|
+
app_source: version2.source,
|
|
5580
|
+
schema: schema.db_version,
|
|
5581
|
+
schema_expected: schema.expected,
|
|
5582
|
+
schema_stale: schema.stale,
|
|
5583
|
+
detector: engineVersion(db, "findings", "SELECT DISTINCT detector_version v FROM findings ORDER BY v", DETECTOR_VERSION),
|
|
5584
|
+
classifier: engineVersion(db, "classifications", "SELECT DISTINCT classifier_version v FROM classifications ORDER BY v", CLASSIFIER_VERSION)
|
|
5585
|
+
},
|
|
5586
|
+
paths: {
|
|
5587
|
+
config_file: resolveConfigFile(ctx.repoRoot, dataDir),
|
|
5588
|
+
data_dir: { path: dataDir, origin: process.env.AGENT_LENS_DATA ? "env" : "default" },
|
|
5589
|
+
// archive and triage_db are "fixed": ADR-021 makes them non-relocatable on their own, so they
|
|
5590
|
+
// are derived here with the same core helpers the CLI uses rather than read from config.
|
|
5591
|
+
archive: { path: resolveArchiveDir(ctx.repoRoot), origin: "fixed" },
|
|
5592
|
+
db: { path: ctx.db.path, origin: ctx.db.origin },
|
|
5593
|
+
triage_db: { path: triageDbFor(ctx.db.path), origin: "fixed" }
|
|
5594
|
+
},
|
|
5595
|
+
server: { host: ctx.host, port: ctx.port, loopback_only: ctx.loopbackOnly },
|
|
5596
|
+
retention: { versions_keep_days: retention.keepDays, origin: retention.origin },
|
|
5597
|
+
sources: loadSources().map((s) => ({ label: s.label, agent: s.agent, config_dir: s.configDir })),
|
|
5598
|
+
// storage() already carries last_ingested from the same MAX(ingested_at) it aggregates over —
|
|
5599
|
+
// reusing it avoids a second query AND keeps the tableExists guard that lastIngested() lacks.
|
|
5600
|
+
storage: storage(db, ctx.db.path)
|
|
5601
|
+
};
|
|
5602
|
+
}
|
|
5603
|
+
|
|
5490
5604
|
// ../server/dist/prefs.js
|
|
5491
5605
|
var PREFS_SCHEMA_SQL = (
|
|
5492
5606
|
/* sql */
|
|
@@ -5548,8 +5662,20 @@ async function createApp(db, opts = {}) {
|
|
|
5548
5662
|
};
|
|
5549
5663
|
app.get("/api/health", async () => {
|
|
5550
5664
|
const s = schemaStatus(db);
|
|
5551
|
-
|
|
5665
|
+
const v = resolveVersion();
|
|
5666
|
+
return {
|
|
5667
|
+
ok: true,
|
|
5668
|
+
last_ingested: lastIngested(db),
|
|
5669
|
+
schema_version: s.db_version,
|
|
5670
|
+
schema_stale: s.stale,
|
|
5671
|
+
version: v.version,
|
|
5672
|
+
version_source: v.source
|
|
5673
|
+
};
|
|
5552
5674
|
});
|
|
5675
|
+
if (opts.about) {
|
|
5676
|
+
const ctx = opts.about;
|
|
5677
|
+
app.get("/api/about", async () => about(db, ctx));
|
|
5678
|
+
}
|
|
5553
5679
|
app.post("/api/refresh", async (req, reply) => {
|
|
5554
5680
|
if (writeBlocked(req.headers)) {
|
|
5555
5681
|
return reply.code(403).send({ error: { code: "FORBIDDEN_ORIGIN", message: "cross-origin refresh blocked" } });
|
|
@@ -5756,9 +5882,9 @@ async function createApp(db, opts = {}) {
|
|
|
5756
5882
|
|
|
5757
5883
|
// ../server/dist/run.js
|
|
5758
5884
|
async function startServer(overrides = {}) {
|
|
5759
|
-
const here =
|
|
5885
|
+
const here = dirname7(fileURLToPath3(import.meta.url));
|
|
5760
5886
|
const repoRoot = findRepoRoot(here);
|
|
5761
|
-
const { path: dbPath } = resolveDbPath(overrides.db);
|
|
5887
|
+
const { path: dbPath, origin: dbOrigin } = resolveDbPath(overrides.db);
|
|
5762
5888
|
const { host, port } = resolveServerConfig({ port: overrides.port, host: overrides.host });
|
|
5763
5889
|
const webDist = resolveWebDist(here, repoRoot);
|
|
5764
5890
|
if (host !== "127.0.0.1" && host !== "localhost" && !process.env.AGENT_LENS_ALLOW_NONLOCAL) {
|
|
@@ -5772,7 +5898,12 @@ async function startServer(overrides = {}) {
|
|
|
5772
5898
|
const triageDbPath = triageDbFor(dbPath);
|
|
5773
5899
|
const db = openReadonly(dbPath);
|
|
5774
5900
|
const enforceLoopbackHost = host === "127.0.0.1" || host === "localhost";
|
|
5775
|
-
const app = await createApp(db, {
|
|
5901
|
+
const app = await createApp(db, {
|
|
5902
|
+
webDist,
|
|
5903
|
+
triageDbPath,
|
|
5904
|
+
enforceLoopbackHost,
|
|
5905
|
+
about: { db: { path: dbPath, origin: dbOrigin }, host, port, loopbackOnly: enforceLoopbackHost, repoRoot }
|
|
5906
|
+
});
|
|
5776
5907
|
try {
|
|
5777
5908
|
await app.listen({ host, port });
|
|
5778
5909
|
console.log(`agent-lens-server: http://${host}:${port} (db: ${dbPath})`);
|
|
@@ -5786,11 +5917,11 @@ async function startServer(overrides = {}) {
|
|
|
5786
5917
|
|
|
5787
5918
|
// src/watch.ts
|
|
5788
5919
|
import { existsSync as existsSync9 } from "fs";
|
|
5789
|
-
import { join as
|
|
5920
|
+
import { join as join11 } from "path";
|
|
5790
5921
|
import chokidar from "chokidar";
|
|
5791
5922
|
async function runWatch(opts = {}) {
|
|
5792
5923
|
const sources = loadSources();
|
|
5793
|
-
const lockPath =
|
|
5924
|
+
const lockPath = join11(resolveDataDir(findRepoRoot()), ".agent-lens.lock");
|
|
5794
5925
|
let running = false;
|
|
5795
5926
|
let pending = false;
|
|
5796
5927
|
const cycle = () => {
|
|
@@ -5823,7 +5954,7 @@ async function runWatch(opts = {}) {
|
|
|
5823
5954
|
}
|
|
5824
5955
|
};
|
|
5825
5956
|
cycle();
|
|
5826
|
-
const watchPaths = sources.map((s) =>
|
|
5957
|
+
const watchPaths = sources.map((s) => join11(s.configDir, "projects")).filter((p) => existsSync9(p));
|
|
5827
5958
|
if (watchPaths.length === 0) {
|
|
5828
5959
|
console.error("agent-lens watch: no source 'projects' directories found \u2014 nothing to watch");
|
|
5829
5960
|
}
|
|
@@ -5850,15 +5981,10 @@ async function runWatch(opts = {}) {
|
|
|
5850
5981
|
|
|
5851
5982
|
// src/index.ts
|
|
5852
5983
|
function version() {
|
|
5853
|
-
|
|
5854
|
-
const pkg = JSON.parse(readFileSync6(join11(dirname7(fileURLToPath3(import.meta.url)), "../package.json"), "utf8"));
|
|
5855
|
-
return pkg.version ?? "0.0.0";
|
|
5856
|
-
} catch {
|
|
5857
|
-
return "0.0.0";
|
|
5858
|
-
}
|
|
5984
|
+
return resolveVersion().version;
|
|
5859
5985
|
}
|
|
5860
5986
|
function withLock(fn) {
|
|
5861
|
-
const lockPath =
|
|
5987
|
+
const lockPath = join12(resolveDataDir(findRepoRoot()), ".agent-lens.lock");
|
|
5862
5988
|
const lock = acquireLock(lockPath);
|
|
5863
5989
|
if (!lock) {
|
|
5864
5990
|
console.error("agent-lens: another collect/ingest run is in progress \u2014 skipping");
|
|
@@ -5926,7 +6052,7 @@ cli.command(
|
|
|
5926
6052
|
).option("--times <hours>", "Collector cadence: comma-separated hours 0-23 (default: 9,13,17,21)").action((action, target, opts) => {
|
|
5927
6053
|
const targets = parseTargets(target);
|
|
5928
6054
|
const hours = action === "install" ? parseHours(opts.times) : void 0;
|
|
5929
|
-
runService(action, { cliEntry:
|
|
6055
|
+
runService(action, { cliEntry: fileURLToPath4(import.meta.url), hours, targets });
|
|
5930
6056
|
});
|
|
5931
6057
|
cli.command("config", "Show the effective configuration (sources, paths, server) and where each value came from").action(() => {
|
|
5932
6058
|
const repoRoot = findRepoRoot();
|
|
@@ -5943,8 +6069,7 @@ cli.command("config", "Show the effective configuration (sources, paths, server)
|
|
|
5943
6069
|
const { path: dbPath, origin: dbOrigin } = resolveDbPath();
|
|
5944
6070
|
const archive = resolveArchiveDir(repoRoot);
|
|
5945
6071
|
const triageDb = triageDbFor(dbPath);
|
|
5946
|
-
const keepDays
|
|
5947
|
-
const keepOrigin = process.env.AGENT_LENS_VERSIONS_KEEP_DAYS ? "env" : "default";
|
|
6072
|
+
const { keepDays, origin: keepOrigin } = resolveRetention();
|
|
5948
6073
|
console.log("agent-lens config (precedence: flag > env > config file > default)\n");
|
|
5949
6074
|
console.log("Paths");
|
|
5950
6075
|
console.log(` config file ${configFile ?? "(none \u2014 using built-in default source)"}`);
|