@swestash/agent-lens 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-lens.js +181 -86
- package/dist/agent-lens.js.map +1 -1
- package/package.json +1 -1
package/dist/agent-lens.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
|
|
5
|
-
import { dirname as dirname6, join as
|
|
5
|
+
import { dirname as dirname6, join as join13 } from "path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7
7
|
|
|
8
8
|
// ../../node_modules/.pnpm/cac@6.7.14/node_modules/cac/dist/index.mjs
|
|
@@ -1339,14 +1339,72 @@ function resolveWebDist(fromDir, repoRoot = findRepoRoot(fromDir)) {
|
|
|
1339
1339
|
return installed;
|
|
1340
1340
|
}
|
|
1341
1341
|
|
|
1342
|
-
// ../core/dist/
|
|
1342
|
+
// ../core/dist/config.js
|
|
1343
1343
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1344
|
-
|
|
1344
|
+
import { join as join2 } from "path";
|
|
1345
|
+
var DEFAULT_PORT = 4477;
|
|
1346
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
1347
|
+
var DEFAULT_DB_NAME = "agent-lens.db";
|
|
1348
|
+
function readConfigFile() {
|
|
1345
1349
|
const repoRoot = findRepoRoot();
|
|
1346
1350
|
const dataDir = resolveDataDir(repoRoot);
|
|
1347
1351
|
const file = resolveConfigFile(repoRoot, dataDir);
|
|
1348
1352
|
return file ? JSON.parse(readFileSync2(file, "utf8")) : null;
|
|
1349
1353
|
}
|
|
1354
|
+
function resolveDbPath(override, cfg = readConfigFile()) {
|
|
1355
|
+
if (override)
|
|
1356
|
+
return { path: override, origin: "flag" };
|
|
1357
|
+
if (process.env.AGENT_LENS_DB)
|
|
1358
|
+
return { path: process.env.AGENT_LENS_DB, origin: "env" };
|
|
1359
|
+
if (isSet(cfg?.db))
|
|
1360
|
+
return { path: expandPath(String(cfg.db).trim()), origin: "file" };
|
|
1361
|
+
return { path: join2(resolveDataDir(findRepoRoot()), DEFAULT_DB_NAME), origin: "default" };
|
|
1362
|
+
}
|
|
1363
|
+
function validatePort(value, source) {
|
|
1364
|
+
const n = typeof value === "number" ? value : Number(String(value).trim());
|
|
1365
|
+
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
1366
|
+
throw new Error(`agent-lens: invalid port from ${source}: '${value}' (expected an integer 1-65535)`);
|
|
1367
|
+
}
|
|
1368
|
+
return n;
|
|
1369
|
+
}
|
|
1370
|
+
function isSet(v) {
|
|
1371
|
+
return v !== void 0 && v !== null && String(v).trim() !== "";
|
|
1372
|
+
}
|
|
1373
|
+
function resolveServerConfig(overrides = {}, cfg = readConfigFile()) {
|
|
1374
|
+
let port;
|
|
1375
|
+
let portOrigin;
|
|
1376
|
+
if (isSet(overrides.port)) {
|
|
1377
|
+
port = validatePort(overrides.port, "--port");
|
|
1378
|
+
portOrigin = "flag";
|
|
1379
|
+
} else if (isSet(process.env.AGENT_LENS_PORT)) {
|
|
1380
|
+
port = validatePort(process.env.AGENT_LENS_PORT, "AGENT_LENS_PORT");
|
|
1381
|
+
portOrigin = "env";
|
|
1382
|
+
} else if (isSet(cfg?.server?.port)) {
|
|
1383
|
+
port = validatePort(cfg.server.port, "server.port (config file)");
|
|
1384
|
+
portOrigin = "file";
|
|
1385
|
+
} else {
|
|
1386
|
+
port = DEFAULT_PORT;
|
|
1387
|
+
portOrigin = "default";
|
|
1388
|
+
}
|
|
1389
|
+
let host;
|
|
1390
|
+
let hostOrigin;
|
|
1391
|
+
if (isSet(overrides.host)) {
|
|
1392
|
+
host = String(overrides.host).trim();
|
|
1393
|
+
hostOrigin = "flag";
|
|
1394
|
+
} else if (isSet(process.env.AGENT_LENS_HOST)) {
|
|
1395
|
+
host = process.env.AGENT_LENS_HOST.trim();
|
|
1396
|
+
hostOrigin = "env";
|
|
1397
|
+
} else if (isSet(cfg?.server?.host)) {
|
|
1398
|
+
host = String(cfg.server.host).trim();
|
|
1399
|
+
hostOrigin = "file";
|
|
1400
|
+
} else {
|
|
1401
|
+
host = DEFAULT_HOST;
|
|
1402
|
+
hostOrigin = "default";
|
|
1403
|
+
}
|
|
1404
|
+
return { port, host, portOrigin, hostOrigin };
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// ../core/dist/sources.js
|
|
1350
1408
|
function loadSources() {
|
|
1351
1409
|
if (process.env.CLAUDE_DIR) {
|
|
1352
1410
|
return [
|
|
@@ -1357,7 +1415,7 @@ function loadSources() {
|
|
|
1357
1415
|
}
|
|
1358
1416
|
];
|
|
1359
1417
|
}
|
|
1360
|
-
const cfg =
|
|
1418
|
+
const cfg = readConfigFile() ?? { sources: [{ label: "default", agent: "claude-code", configDir: "$HOME/.claude" }] };
|
|
1361
1419
|
const seen = /* @__PURE__ */ new Set();
|
|
1362
1420
|
const out = [];
|
|
1363
1421
|
for (const raw of cfg.sources || []) {
|
|
@@ -1377,7 +1435,7 @@ function loadExcludes() {
|
|
|
1377
1435
|
const fromEnv = (process.env.AGENT_LENS_EXCLUDE || "").split(",");
|
|
1378
1436
|
let fromCfg = [];
|
|
1379
1437
|
if (!process.env.CLAUDE_DIR) {
|
|
1380
|
-
const cfg =
|
|
1438
|
+
const cfg = readConfigFile();
|
|
1381
1439
|
if (cfg && Array.isArray(cfg.exclude))
|
|
1382
1440
|
fromCfg = cfg.exclude;
|
|
1383
1441
|
}
|
|
@@ -1400,7 +1458,7 @@ function encodeProjectPath(p) {
|
|
|
1400
1458
|
|
|
1401
1459
|
// ../core/dist/collect.js
|
|
1402
1460
|
import { appendFileSync, closeSync, copyFileSync, existsSync as existsSync2, mkdirSync, openSync, readSync, readdirSync, statSync, unlinkSync, utimesSync, writeSync, chmodSync } from "fs";
|
|
1403
|
-
import { basename, dirname as dirname2, join as
|
|
1461
|
+
import { basename, dirname as dirname2, join as join3, relative, sep } from "path";
|
|
1404
1462
|
import { platform as platform2 } from "os";
|
|
1405
1463
|
var POSIX = platform2() !== "win32";
|
|
1406
1464
|
var DIR_MODE = 448;
|
|
@@ -1480,19 +1538,19 @@ function filesEqual(a, b) {
|
|
|
1480
1538
|
return prefixEquals(a, b, sa.size);
|
|
1481
1539
|
}
|
|
1482
1540
|
function latestSnapshot(archive, relParts) {
|
|
1483
|
-
const versRoot =
|
|
1541
|
+
const versRoot = join3(archive, ".versions");
|
|
1484
1542
|
if (!existsSync2(versRoot))
|
|
1485
1543
|
return null;
|
|
1486
1544
|
const stamps = readdirSync(versRoot).sort();
|
|
1487
1545
|
for (let i = stamps.length - 1; i >= 0; i--) {
|
|
1488
|
-
const p =
|
|
1546
|
+
const p = join3(versRoot, stamps[i], ...relParts);
|
|
1489
1547
|
if (existsSync2(p))
|
|
1490
1548
|
return p;
|
|
1491
1549
|
}
|
|
1492
1550
|
return null;
|
|
1493
1551
|
}
|
|
1494
1552
|
function snapshot(absPath, relParts, versionsDir, stats) {
|
|
1495
|
-
const dst =
|
|
1553
|
+
const dst = join3(versionsDir, ...relParts);
|
|
1496
1554
|
ensureDir(dirname2(dst));
|
|
1497
1555
|
copyFileSync(absPath, dst);
|
|
1498
1556
|
syncMeta(dst, statSync(absPath));
|
|
@@ -1500,7 +1558,7 @@ function snapshot(absPath, relParts, versionsDir, stats) {
|
|
|
1500
1558
|
}
|
|
1501
1559
|
function walkCollectable(dir, out, inWorkflows = false, inToolResults = false) {
|
|
1502
1560
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
1503
|
-
const p =
|
|
1561
|
+
const p = join3(dir, e.name);
|
|
1504
1562
|
if (e.isDirectory()) {
|
|
1505
1563
|
walkCollectable(p, out, inWorkflows || e.name === "workflows", inToolResults || e.name === "tool-results");
|
|
1506
1564
|
} else if (e.isFile() && (e.name.endsWith(".jsonl") || inWorkflows || inToolResults || e.name.endsWith(".meta.json"))) {
|
|
@@ -1541,7 +1599,7 @@ function removeCredentials(dir) {
|
|
|
1541
1599
|
if (!existsSync2(dir))
|
|
1542
1600
|
return;
|
|
1543
1601
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
1544
|
-
const p =
|
|
1602
|
+
const p = join3(dir, e.name);
|
|
1545
1603
|
if (e.isDirectory())
|
|
1546
1604
|
removeCredentials(p);
|
|
1547
1605
|
else if (e.name === ".credentials.json") {
|
|
@@ -1554,19 +1612,19 @@ function removeCredentials(dir) {
|
|
|
1554
1612
|
}
|
|
1555
1613
|
function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
1556
1614
|
const { label, configDir } = source;
|
|
1557
|
-
const archive =
|
|
1558
|
-
const versionsDir =
|
|
1615
|
+
const archive = join3(archiveBase, label);
|
|
1616
|
+
const versionsDir = join3(archive, ".versions", runTs);
|
|
1559
1617
|
if (!existsSync2(configDir)) {
|
|
1560
1618
|
log(`agent-lens: [${label}] source not found: ${configDir} (skipping)`);
|
|
1561
1619
|
return;
|
|
1562
1620
|
}
|
|
1563
|
-
ensureDir(
|
|
1564
|
-
ensureDir(
|
|
1621
|
+
ensureDir(join3(archive, "projects"));
|
|
1622
|
+
ensureDir(join3(archive, "settings"));
|
|
1565
1623
|
const files = [];
|
|
1566
|
-
const projectsDir =
|
|
1624
|
+
const projectsDir = join3(configDir, "projects");
|
|
1567
1625
|
if (existsSync2(projectsDir))
|
|
1568
1626
|
walkCollectable(projectsDir, files);
|
|
1569
|
-
const historySrc =
|
|
1627
|
+
const historySrc = join3(configDir, "history.jsonl");
|
|
1570
1628
|
if (existsSync2(historySrc))
|
|
1571
1629
|
files.push(historySrc);
|
|
1572
1630
|
const before = { scanned: stats.scanned, snapshots: stats.snapshots };
|
|
@@ -1579,13 +1637,13 @@ function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
|
1579
1637
|
if (excludedDirs.some((enc) => relPosix.startsWith(`projects/${enc}/`)))
|
|
1580
1638
|
continue;
|
|
1581
1639
|
stats.scanned++;
|
|
1582
|
-
syncFile(src,
|
|
1640
|
+
syncFile(src, join3(archive, ...relParts), relParts, archive, versionsDir, stats, base.endsWith(".jsonl"));
|
|
1583
1641
|
}
|
|
1584
1642
|
for (const f of ["settings.json", "settings.local.json"]) {
|
|
1585
|
-
const s =
|
|
1643
|
+
const s = join3(configDir, f);
|
|
1586
1644
|
if (!existsSync2(s))
|
|
1587
1645
|
continue;
|
|
1588
|
-
const a =
|
|
1646
|
+
const a = join3(archive, "settings", f);
|
|
1589
1647
|
if (existsSync2(a) && !filesEqual(s, a))
|
|
1590
1648
|
snapshot(a, ["settings", f], versionsDir, stats);
|
|
1591
1649
|
ensureDir(dirname2(a));
|
|
@@ -1598,13 +1656,13 @@ function collectSource(source, archiveBase, excludedDirs, runTs, stats, log) {
|
|
|
1598
1656
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} run=${runTs} source=${label} scanned=${scanned} snapshots=${snapshots} archive=${archive}`;
|
|
1599
1657
|
log(`agent-lens: ${line}`);
|
|
1600
1658
|
try {
|
|
1601
|
-
appendFileSync(
|
|
1659
|
+
appendFileSync(join3(archiveBase, ".collect.log"), line + "\n");
|
|
1602
1660
|
} catch {
|
|
1603
1661
|
}
|
|
1604
1662
|
}
|
|
1605
1663
|
function collectAll(opts = {}) {
|
|
1606
1664
|
const log = opts.log ?? ((m) => console.log(m));
|
|
1607
|
-
const archiveBase = opts.archiveBase ??
|
|
1665
|
+
const archiveBase = opts.archiveBase ?? join3(resolveDataDir(findRepoRoot()), "archive");
|
|
1608
1666
|
const sources = opts.sources ?? loadSources();
|
|
1609
1667
|
const excludedDirs = (opts.excludes ?? loadExcludes()).map(encodeProjectPath);
|
|
1610
1668
|
const runTs = opts.runTimestamp ?? collectTimestamp();
|
|
@@ -1665,7 +1723,7 @@ function acquireLock(lockPath, staleMs = 6 * 60 * 60 * 1e3) {
|
|
|
1665
1723
|
import { spawnSync } from "child_process";
|
|
1666
1724
|
import { mkdirSync as mkdirSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1667
1725
|
import { homedir as homedir2, platform as platform3 } from "os";
|
|
1668
|
-
import { join as
|
|
1726
|
+
import { join as join4 } from "path";
|
|
1669
1727
|
var DEFAULT_HOURS = [9, 13, 17, 21];
|
|
1670
1728
|
var SYSTEMD_COLLECTOR_TIMER = "agent-lens-collect.timer";
|
|
1671
1729
|
var SYSTEMD_COLLECTOR_SERVICE = "agent-lens-collect.service";
|
|
@@ -1691,10 +1749,11 @@ function parseHours(spec) {
|
|
|
1691
1749
|
}
|
|
1692
1750
|
function serverEnv() {
|
|
1693
1751
|
const env = {};
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1752
|
+
const { port, host, portOrigin, hostOrigin } = resolveServerConfig();
|
|
1753
|
+
if (portOrigin !== "default")
|
|
1754
|
+
env.AGENT_LENS_PORT = String(port);
|
|
1755
|
+
if (hostOrigin !== "default")
|
|
1756
|
+
env.AGENT_LENS_HOST = host;
|
|
1698
1757
|
return env;
|
|
1699
1758
|
}
|
|
1700
1759
|
function onCalendarHours(hours) {
|
|
@@ -1807,7 +1866,7 @@ function have(cmd) {
|
|
|
1807
1866
|
return r.status === 0 || r.error === void 0;
|
|
1808
1867
|
}
|
|
1809
1868
|
function systemdUnitDir() {
|
|
1810
|
-
return
|
|
1869
|
+
return join4(process.env.XDG_CONFIG_HOME || join4(homedir2(), ".config"), "systemd", "user");
|
|
1811
1870
|
}
|
|
1812
1871
|
function linuxInstall(targets, node, cli2, hours) {
|
|
1813
1872
|
if (!have("systemctl")) {
|
|
@@ -1818,11 +1877,11 @@ function linuxInstall(targets, node, cli2, hours) {
|
|
|
1818
1877
|
const dir = systemdUnitDir();
|
|
1819
1878
|
mkdirSync3(dir, { recursive: true });
|
|
1820
1879
|
if (targets.includes("collector")) {
|
|
1821
|
-
writeFileSync2(
|
|
1822
|
-
writeFileSync2(
|
|
1880
|
+
writeFileSync2(join4(dir, SYSTEMD_COLLECTOR_SERVICE), systemdCollectorService(node, cli2));
|
|
1881
|
+
writeFileSync2(join4(dir, SYSTEMD_COLLECTOR_TIMER), systemdCollectorTimer(hours));
|
|
1823
1882
|
}
|
|
1824
1883
|
if (targets.includes("server")) {
|
|
1825
|
-
writeFileSync2(
|
|
1884
|
+
writeFileSync2(join4(dir, SYSTEMD_SERVER_SERVICE), systemdServerService(node, cli2, serverEnv()));
|
|
1826
1885
|
}
|
|
1827
1886
|
sh("systemctl", ["--user", "daemon-reload"]);
|
|
1828
1887
|
if (targets.includes("collector")) {
|
|
@@ -1846,12 +1905,12 @@ function linuxUninstall(targets) {
|
|
|
1846
1905
|
if (targets.includes("collector")) {
|
|
1847
1906
|
sh("systemctl", ["--user", "disable", "--now", SYSTEMD_COLLECTOR_TIMER], true);
|
|
1848
1907
|
for (const u of [SYSTEMD_COLLECTOR_TIMER, SYSTEMD_COLLECTOR_SERVICE])
|
|
1849
|
-
rmSync(
|
|
1908
|
+
rmSync(join4(dir, u), { force: true });
|
|
1850
1909
|
sh("systemctl", ["--user", "reset-failed", SYSTEMD_COLLECTOR_SERVICE], true);
|
|
1851
1910
|
}
|
|
1852
1911
|
if (targets.includes("server")) {
|
|
1853
1912
|
sh("systemctl", ["--user", "disable", "--now", SYSTEMD_SERVER_SERVICE], true);
|
|
1854
|
-
rmSync(
|
|
1913
|
+
rmSync(join4(dir, SYSTEMD_SERVER_SERVICE), { force: true });
|
|
1855
1914
|
sh("systemctl", ["--user", "reset-failed", SYSTEMD_SERVER_SERVICE], true);
|
|
1856
1915
|
}
|
|
1857
1916
|
sh("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -1866,7 +1925,7 @@ function linuxStatus(targets) {
|
|
|
1866
1925
|
sh("systemctl", ["--user", "status", SYSTEMD_SERVER_SERVICE, "--no-pager"]);
|
|
1867
1926
|
}
|
|
1868
1927
|
function launchdPlistPath(label) {
|
|
1869
|
-
return
|
|
1928
|
+
return join4(homedir2(), "Library", "LaunchAgents", `${label}.plist`);
|
|
1870
1929
|
}
|
|
1871
1930
|
function macBootstrap(plist) {
|
|
1872
1931
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
@@ -1880,18 +1939,18 @@ function macBootout(label, plist) {
|
|
|
1880
1939
|
rmSync(plist, { force: true });
|
|
1881
1940
|
}
|
|
1882
1941
|
function macInstall(targets, node, cli2, hours) {
|
|
1883
|
-
const agents =
|
|
1942
|
+
const agents = join4(homedir2(), "Library", "LaunchAgents");
|
|
1884
1943
|
mkdirSync3(agents, { recursive: true });
|
|
1885
1944
|
const dataDir = resolveDataDir(findRepoRoot());
|
|
1886
1945
|
if (targets.includes("collector")) {
|
|
1887
1946
|
const plist = launchdPlistPath(LAUNCHD_COLLECTOR_LABEL);
|
|
1888
|
-
writeFileSync2(plist, launchdCollectorPlist(node, cli2, hours,
|
|
1947
|
+
writeFileSync2(plist, launchdCollectorPlist(node, cli2, hours, join4(dataDir, "schedule.log")));
|
|
1889
1948
|
macBootstrap(plist);
|
|
1890
1949
|
console.log(`agent-lens service: installed collector agent ${LAUNCHD_COLLECTOR_LABEL} (hours ${hours.join(",")})`);
|
|
1891
1950
|
}
|
|
1892
1951
|
if (targets.includes("server")) {
|
|
1893
1952
|
const plist = launchdPlistPath(LAUNCHD_SERVER_LABEL);
|
|
1894
|
-
writeFileSync2(plist, launchdServerPlist(node, cli2,
|
|
1953
|
+
writeFileSync2(plist, launchdServerPlist(node, cli2, join4(dataDir, "server.log"), serverEnv()));
|
|
1895
1954
|
macBootstrap(plist);
|
|
1896
1955
|
console.log(`agent-lens service: installed server agent ${LAUNCHD_SERVER_LABEL}`);
|
|
1897
1956
|
}
|
|
@@ -1982,7 +2041,7 @@ function runService(action, params) {
|
|
|
1982
2041
|
|
|
1983
2042
|
// ../ingest/dist/run.js
|
|
1984
2043
|
import { readFileSync as readFileSync7, statSync as statSync5, mkdirSync as mkdirSync4, existsSync as existsSync4 } from "fs";
|
|
1985
|
-
import { dirname as dirname4, join as
|
|
2044
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
1986
2045
|
|
|
1987
2046
|
// ../ingest/dist/db.js
|
|
1988
2047
|
import Database from "better-sqlite3";
|
|
@@ -2038,7 +2097,7 @@ function resetSchema(db) {
|
|
|
2038
2097
|
|
|
2039
2098
|
// ../ingest/dist/adapters/claude-code.js
|
|
2040
2099
|
import { readdirSync as readdirSync2 } from "fs";
|
|
2041
|
-
import { basename as basename2, join as
|
|
2100
|
+
import { basename as basename2, join as join5 } from "path";
|
|
2042
2101
|
function flattenText(content) {
|
|
2043
2102
|
if (content == null)
|
|
2044
2103
|
return null;
|
|
@@ -2121,7 +2180,7 @@ function recurseJsonl(dir, out) {
|
|
|
2121
2180
|
return;
|
|
2122
2181
|
}
|
|
2123
2182
|
for (const e of entries) {
|
|
2124
|
-
const p =
|
|
2183
|
+
const p = join5(dir, e.name);
|
|
2125
2184
|
if (e.isDirectory())
|
|
2126
2185
|
recurseJsonl(p, out);
|
|
2127
2186
|
else if (e.isFile() && e.name.endsWith(".jsonl"))
|
|
@@ -2152,12 +2211,12 @@ var ClaudeCodeAdapter = class {
|
|
|
2152
2211
|
});
|
|
2153
2212
|
}
|
|
2154
2213
|
};
|
|
2155
|
-
addFrom(
|
|
2156
|
-
const versionsRoot =
|
|
2214
|
+
addFrom(join5(archiveRoot, "projects"), false);
|
|
2215
|
+
const versionsRoot = join5(archiveRoot, ".versions");
|
|
2157
2216
|
try {
|
|
2158
2217
|
for (const ts of readdirSync2(versionsRoot, { withFileTypes: true })) {
|
|
2159
2218
|
if (ts.isDirectory())
|
|
2160
|
-
addFrom(
|
|
2219
|
+
addFrom(join5(versionsRoot, ts.name, "projects"), true);
|
|
2161
2220
|
}
|
|
2162
2221
|
} catch {
|
|
2163
2222
|
}
|
|
@@ -3584,7 +3643,7 @@ function ingestFile(db, stmts, adapter, file, lines, meta, now2, stats) {
|
|
|
3584
3643
|
|
|
3585
3644
|
// ../ingest/dist/workflows.js
|
|
3586
3645
|
import { readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
3587
|
-
import { basename as basename3, join as
|
|
3646
|
+
import { basename as basename3, join as join6 } from "path";
|
|
3588
3647
|
|
|
3589
3648
|
// ../ingest/dist/redact.js
|
|
3590
3649
|
import { createHash as createHash4, randomBytes } from "crypto";
|
|
@@ -3652,7 +3711,7 @@ function walkSidecars(dir, inWorkflows, out) {
|
|
|
3652
3711
|
return;
|
|
3653
3712
|
}
|
|
3654
3713
|
for (const e of entries) {
|
|
3655
|
-
const p =
|
|
3714
|
+
const p = join6(dir, e.name);
|
|
3656
3715
|
if (e.isDirectory())
|
|
3657
3716
|
walkSidecars(p, inWorkflows || e.name === "workflows", out);
|
|
3658
3717
|
else if (e.isFile() && inWorkflows && /^wf_.+\.json$/.test(e.name))
|
|
@@ -3661,11 +3720,11 @@ function walkSidecars(dir, inWorkflows, out) {
|
|
|
3661
3720
|
}
|
|
3662
3721
|
function discoverSidecars(sourceArchiveDir) {
|
|
3663
3722
|
const out = [];
|
|
3664
|
-
walkSidecars(
|
|
3723
|
+
walkSidecars(join6(sourceArchiveDir, "projects"), false, out);
|
|
3665
3724
|
try {
|
|
3666
|
-
for (const ts of readdirSync3(
|
|
3725
|
+
for (const ts of readdirSync3(join6(sourceArchiveDir, ".versions"), { withFileTypes: true }))
|
|
3667
3726
|
if (ts.isDirectory())
|
|
3668
|
-
walkSidecars(
|
|
3727
|
+
walkSidecars(join6(sourceArchiveDir, ts.name, "projects"), false, out);
|
|
3669
3728
|
} catch {
|
|
3670
3729
|
}
|
|
3671
3730
|
return out;
|
|
@@ -3783,7 +3842,7 @@ function ingestWorkflowResults(db, sourceArchiveDir, sourceId, excludedDirs, now
|
|
|
3783
3842
|
|
|
3784
3843
|
// ../ingest/dist/meta.js
|
|
3785
3844
|
import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
3786
|
-
import { basename as basename4, join as
|
|
3845
|
+
import { basename as basename4, join as join7 } from "path";
|
|
3787
3846
|
function newMetaStats() {
|
|
3788
3847
|
return { files: 0, upserted: 0, skipped: 0, malformed: 0 };
|
|
3789
3848
|
}
|
|
@@ -3795,7 +3854,7 @@ function walkMeta(dir, inSubagents, out) {
|
|
|
3795
3854
|
return;
|
|
3796
3855
|
}
|
|
3797
3856
|
for (const e of entries) {
|
|
3798
|
-
const p =
|
|
3857
|
+
const p = join7(dir, e.name);
|
|
3799
3858
|
if (e.isDirectory())
|
|
3800
3859
|
walkMeta(p, inSubagents || e.name === "subagents", out);
|
|
3801
3860
|
else if (e.isFile() && inSubagents && /^agent-.+\.meta\.json$/.test(e.name))
|
|
@@ -3804,11 +3863,11 @@ function walkMeta(dir, inSubagents, out) {
|
|
|
3804
3863
|
}
|
|
3805
3864
|
function discoverMeta(sourceArchiveDir) {
|
|
3806
3865
|
const out = [];
|
|
3807
|
-
walkMeta(
|
|
3866
|
+
walkMeta(join7(sourceArchiveDir, "projects"), false, out);
|
|
3808
3867
|
try {
|
|
3809
|
-
for (const ts of readdirSync4(
|
|
3868
|
+
for (const ts of readdirSync4(join7(sourceArchiveDir, ".versions"), { withFileTypes: true }))
|
|
3810
3869
|
if (ts.isDirectory())
|
|
3811
|
-
walkMeta(
|
|
3870
|
+
walkMeta(join7(sourceArchiveDir, ts.name, "projects"), false, out);
|
|
3812
3871
|
} catch {
|
|
3813
3872
|
}
|
|
3814
3873
|
return out;
|
|
@@ -3882,7 +3941,7 @@ function ingestSubagentMeta(db, sourceArchiveDir, sourceId, excludedDirs, now2,
|
|
|
3882
3941
|
|
|
3883
3942
|
// ../ingest/dist/toolResults.js
|
|
3884
3943
|
import { readdirSync as readdirSync5, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
3885
|
-
import { basename as basename5, join as
|
|
3944
|
+
import { basename as basename5, join as join8 } from "path";
|
|
3886
3945
|
function newToolResultStats() {
|
|
3887
3946
|
return { files: 0, upserted: 0, skipped: 0, malformed: 0 };
|
|
3888
3947
|
}
|
|
@@ -3894,7 +3953,7 @@ function walkResults(dir, inResults, out) {
|
|
|
3894
3953
|
return;
|
|
3895
3954
|
}
|
|
3896
3955
|
for (const e of entries) {
|
|
3897
|
-
const p =
|
|
3956
|
+
const p = join8(dir, e.name);
|
|
3898
3957
|
if (e.isDirectory())
|
|
3899
3958
|
walkResults(p, inResults || e.name === "tool-results", out);
|
|
3900
3959
|
else if (e.isFile() && inResults && e.name.endsWith(".txt"))
|
|
@@ -3903,11 +3962,11 @@ function walkResults(dir, inResults, out) {
|
|
|
3903
3962
|
}
|
|
3904
3963
|
function discoverResults(sourceArchiveDir) {
|
|
3905
3964
|
const out = [];
|
|
3906
|
-
walkResults(
|
|
3965
|
+
walkResults(join8(sourceArchiveDir, "projects"), false, out);
|
|
3907
3966
|
try {
|
|
3908
|
-
for (const ts of readdirSync5(
|
|
3967
|
+
for (const ts of readdirSync5(join8(sourceArchiveDir, ".versions"), { withFileTypes: true }))
|
|
3909
3968
|
if (ts.isDirectory())
|
|
3910
|
-
walkResults(
|
|
3969
|
+
walkResults(join8(sourceArchiveDir, ts.name, "projects"), false, out);
|
|
3911
3970
|
} catch {
|
|
3912
3971
|
}
|
|
3913
3972
|
return out;
|
|
@@ -3984,8 +4043,8 @@ function parseIngestArgs(argv) {
|
|
|
3984
4043
|
function runIngest(argv = process.argv.slice(2)) {
|
|
3985
4044
|
const args = parseIngestArgs(argv);
|
|
3986
4045
|
const dataDir = resolveDataDir(findRepoRoot());
|
|
3987
|
-
const archiveRoot = args.archive || process.env.AGENT_LENS_ARCHIVE ||
|
|
3988
|
-
const
|
|
4046
|
+
const archiveRoot = args.archive || process.env.AGENT_LENS_ARCHIVE || join9(dataDir, "archive");
|
|
4047
|
+
const { path: dbPath } = resolveDbPath(args.db);
|
|
3989
4048
|
if (!existsSync4(archiveRoot)) {
|
|
3990
4049
|
console.error(`agent-lens-ingest: archive not found: ${archiveRoot} (run 'agent-lens collect' first)`);
|
|
3991
4050
|
process.exit(1);
|
|
@@ -4023,7 +4082,7 @@ function runIngest(argv = process.argv.slice(2)) {
|
|
|
4023
4082
|
}
|
|
4024
4083
|
stmts.insAgent.run(adapter.agentId, adapter.agentName);
|
|
4025
4084
|
stmts.insSource.run({ id: source.label, label: source.label, agent_id: adapter.agentId, config_dir: source.configDir });
|
|
4026
|
-
let files = adapter.discover(
|
|
4085
|
+
let files = adapter.discover(join9(archiveRoot, source.label), source.label);
|
|
4027
4086
|
if (excludedDirs.length)
|
|
4028
4087
|
files = files.filter((f) => !isExcludedArchivePath(f.path, excludedDirs));
|
|
4029
4088
|
files.sort((a, b) => Number(a.isVersion) - Number(b.isVersion));
|
|
@@ -4055,9 +4114,9 @@ function runIngest(argv = process.argv.slice(2)) {
|
|
|
4055
4114
|
ingestFile(db, stmts, adapter, file, lines, { size: st.size, mtimeMs, hash: hash2 }, now2, stats);
|
|
4056
4115
|
dirty.add(file.sessionId);
|
|
4057
4116
|
}
|
|
4058
|
-
ingestWorkflowResults(db,
|
|
4059
|
-
ingestSubagentMeta(db,
|
|
4060
|
-
ingestToolResults(db,
|
|
4117
|
+
ingestWorkflowResults(db, join9(archiveRoot, source.label), source.label, excludedDirs, now2, wfStats, args.full);
|
|
4118
|
+
ingestSubagentMeta(db, join9(archiveRoot, source.label), source.label, excludedDirs, now2, metaStats, args.full);
|
|
4119
|
+
ingestToolResults(db, join9(archiveRoot, source.label), excludedDirs, now2, trStats, args.full);
|
|
4061
4120
|
}
|
|
4062
4121
|
const expanded = rebuildDerived(db, args.full ? null : dirty);
|
|
4063
4122
|
const classified = classify(db, args.full ? null : expanded);
|
|
@@ -4095,8 +4154,7 @@ function runMetrics(argv = process.argv.slice(2)) {
|
|
|
4095
4154
|
for (let i = 0; i < argv.length; i++)
|
|
4096
4155
|
if (argv[i] === "--db")
|
|
4097
4156
|
dbArg = argv[++i] ?? "";
|
|
4098
|
-
const
|
|
4099
|
-
const dbPath = dbArg || process.env.AGENT_LENS_DB || join8(dataDir, "agent-lens.db");
|
|
4157
|
+
const { path: dbPath } = resolveDbPath(dbArg);
|
|
4100
4158
|
if (!existsSync4(dbPath)) {
|
|
4101
4159
|
console.error(`agent-lens-metrics: db not found: ${dbPath} (run ingest first)`);
|
|
4102
4160
|
process.exit(1);
|
|
@@ -4111,7 +4169,7 @@ function runMetrics(argv = process.argv.slice(2)) {
|
|
|
4111
4169
|
|
|
4112
4170
|
// ../server/dist/run.js
|
|
4113
4171
|
import { existsSync as existsSync7 } from "fs";
|
|
4114
|
-
import { dirname as dirname5, join as
|
|
4172
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
4115
4173
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4116
4174
|
|
|
4117
4175
|
// ../server/dist/db.js
|
|
@@ -4967,7 +5025,7 @@ function dashboardBreakdowns(db, f) {
|
|
|
4967
5025
|
|
|
4968
5026
|
// ../server/dist/refresh.js
|
|
4969
5027
|
import { existsSync as existsSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
4970
|
-
import { join as
|
|
5028
|
+
import { join as join10 } from "path";
|
|
4971
5029
|
function originAllowed(origin) {
|
|
4972
5030
|
if (!origin)
|
|
4973
5031
|
return true;
|
|
@@ -4988,12 +5046,12 @@ function writeBlocked(headers) {
|
|
|
4988
5046
|
}
|
|
4989
5047
|
function runRefresh() {
|
|
4990
5048
|
const dataDir = resolveDataDir(findRepoRoot());
|
|
4991
|
-
const lock = acquireLock(
|
|
5049
|
+
const lock = acquireLock(join10(dataDir, ".agent-lens.lock"));
|
|
4992
5050
|
if (!lock)
|
|
4993
5051
|
return null;
|
|
4994
5052
|
try {
|
|
4995
5053
|
const collected = collectAll();
|
|
4996
|
-
const archiveRoot = process.env.AGENT_LENS_ARCHIVE ||
|
|
5054
|
+
const archiveRoot = process.env.AGENT_LENS_ARCHIVE || join10(dataDir, "archive");
|
|
4997
5055
|
if (!existsSync5(archiveRoot))
|
|
4998
5056
|
mkdirSync5(archiveRoot, { recursive: true });
|
|
4999
5057
|
runIngest([]);
|
|
@@ -5309,12 +5367,11 @@ async function createApp(db, opts = {}) {
|
|
|
5309
5367
|
}
|
|
5310
5368
|
|
|
5311
5369
|
// ../server/dist/run.js
|
|
5312
|
-
async function startServer() {
|
|
5370
|
+
async function startServer(overrides = {}) {
|
|
5313
5371
|
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
5314
5372
|
const repoRoot = findRepoRoot(here);
|
|
5315
|
-
const dbPath =
|
|
5316
|
-
const host =
|
|
5317
|
-
const port = Number(process.env.AGENT_LENS_PORT || 4477);
|
|
5373
|
+
const { path: dbPath } = resolveDbPath(overrides.db);
|
|
5374
|
+
const { host, port } = resolveServerConfig({ port: overrides.port, host: overrides.host });
|
|
5318
5375
|
const webDist = resolveWebDist(here, repoRoot);
|
|
5319
5376
|
if (host !== "127.0.0.1" && host !== "localhost" && !process.env.AGENT_LENS_ALLOW_NONLOCAL) {
|
|
5320
5377
|
console.error(`agent-lens-server: refusing to bind non-loopback host '${host}' (privacy). Set AGENT_LENS_ALLOW_NONLOCAL=1 to override.`);
|
|
@@ -5324,7 +5381,7 @@ async function startServer() {
|
|
|
5324
5381
|
console.error(`agent-lens-server: db not found: ${dbPath} (run ingest first)`);
|
|
5325
5382
|
process.exit(1);
|
|
5326
5383
|
}
|
|
5327
|
-
const triageDbPath = process.env.AGENT_LENS_TRIAGE_DB ||
|
|
5384
|
+
const triageDbPath = process.env.AGENT_LENS_TRIAGE_DB || join11(dirname5(dbPath), "triage.db");
|
|
5328
5385
|
const db = openReadonly(dbPath);
|
|
5329
5386
|
const enforceLoopbackHost = host === "127.0.0.1" || host === "localhost";
|
|
5330
5387
|
const app = await createApp(db, { webDist, triageDbPath, enforceLoopbackHost });
|
|
@@ -5341,11 +5398,11 @@ async function startServer() {
|
|
|
5341
5398
|
|
|
5342
5399
|
// src/watch.ts
|
|
5343
5400
|
import { existsSync as existsSync8 } from "fs";
|
|
5344
|
-
import { join as
|
|
5401
|
+
import { join as join12 } from "path";
|
|
5345
5402
|
import chokidar from "chokidar";
|
|
5346
5403
|
async function runWatch(opts = {}) {
|
|
5347
5404
|
const sources = loadSources();
|
|
5348
|
-
const lockPath =
|
|
5405
|
+
const lockPath = join12(resolveDataDir(findRepoRoot()), ".agent-lens.lock");
|
|
5349
5406
|
let running = false;
|
|
5350
5407
|
let pending = false;
|
|
5351
5408
|
const cycle = () => {
|
|
@@ -5378,7 +5435,7 @@ async function runWatch(opts = {}) {
|
|
|
5378
5435
|
}
|
|
5379
5436
|
};
|
|
5380
5437
|
cycle();
|
|
5381
|
-
const watchPaths = sources.map((s) =>
|
|
5438
|
+
const watchPaths = sources.map((s) => join12(s.configDir, "projects")).filter((p) => existsSync8(p));
|
|
5382
5439
|
if (watchPaths.length === 0) {
|
|
5383
5440
|
console.error("agent-lens watch: no source 'projects' directories found \u2014 nothing to watch");
|
|
5384
5441
|
}
|
|
@@ -5406,14 +5463,14 @@ async function runWatch(opts = {}) {
|
|
|
5406
5463
|
// src/index.ts
|
|
5407
5464
|
function version() {
|
|
5408
5465
|
try {
|
|
5409
|
-
const pkg = JSON.parse(readFileSync8(
|
|
5466
|
+
const pkg = JSON.parse(readFileSync8(join13(dirname6(fileURLToPath3(import.meta.url)), "../package.json"), "utf8"));
|
|
5410
5467
|
return pkg.version ?? "0.0.0";
|
|
5411
5468
|
} catch {
|
|
5412
5469
|
return "0.0.0";
|
|
5413
5470
|
}
|
|
5414
5471
|
}
|
|
5415
5472
|
function withLock(fn) {
|
|
5416
|
-
const lockPath =
|
|
5473
|
+
const lockPath = join13(resolveDataDir(findRepoRoot()), ".agent-lens.lock");
|
|
5417
5474
|
const lock = acquireLock(lockPath);
|
|
5418
5475
|
if (!lock) {
|
|
5419
5476
|
console.error("agent-lens: another collect/ingest run is in progress \u2014 skipping");
|
|
@@ -5435,24 +5492,29 @@ cli.command("collect", "Copy new session traces into the local archive").option(
|
|
|
5435
5492
|
if (opts.thenIngest) runIngest([]);
|
|
5436
5493
|
});
|
|
5437
5494
|
});
|
|
5438
|
-
cli.command("ingest", "Build/update the SQLite projection from the archive").option("--full", "Ignore incremental state and re-read every file").option("--db <path>", "SQLite DB path").option("--archive <path>", "Archive directory").action((opts) => {
|
|
5495
|
+
cli.command("ingest", "Build/update the SQLite projection from the archive").option("--full", "Ignore incremental state and re-read every file").option("--db <path>", "SQLite DB path (overrides AGENT_LENS_DB / config db)").option("--archive <path>", "Archive directory").action((opts) => {
|
|
5439
5496
|
const argv = [];
|
|
5440
5497
|
if (opts.full) argv.push("--full");
|
|
5441
5498
|
if (opts.db) argv.push("--db", opts.db);
|
|
5442
5499
|
if (opts.archive) argv.push("--archive", opts.archive);
|
|
5443
5500
|
withLock(() => runIngest(argv));
|
|
5444
5501
|
});
|
|
5445
|
-
cli.command("serve", "Serve the web UI + read-only API on 127.0.0.1").action(async () => {
|
|
5446
|
-
|
|
5502
|
+
cli.command("serve", "Serve the web UI + read-only API on 127.0.0.1").option("--port <n>", "HTTP port (overrides AGENT_LENS_PORT / config server.port; default 4477)").option("--host <host>", "Bind host (overrides AGENT_LENS_HOST / config server.host; loopback only unless AGENT_LENS_ALLOW_NONLOCAL=1)").option("--db <path>", "SQLite DB path (overrides AGENT_LENS_DB / config db)").action(async (opts) => {
|
|
5503
|
+
try {
|
|
5504
|
+
await startServer({ port: opts.port, host: opts.host, db: opts.db });
|
|
5505
|
+
} catch (e) {
|
|
5506
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
5507
|
+
process.exit(1);
|
|
5508
|
+
}
|
|
5447
5509
|
});
|
|
5448
5510
|
cli.command("watch", "Watch sources and collect + ingest on change (resident process)").option("--interval <sec>", "Also run on a fixed interval (seconds)").option("--poll", "Use polling \u2014 for network filesystems where fs events don't fire").action(async (opts) => {
|
|
5449
5511
|
await runWatch({ intervalSec: opts.interval ? Number(opts.interval) : void 0, poll: !!opts.poll });
|
|
5450
5512
|
});
|
|
5451
|
-
cli.command("metrics", "Re-run classification over an already-ingested DB").option("--db <path>", "SQLite DB path").action((opts) => {
|
|
5513
|
+
cli.command("metrics", "Re-run classification over an already-ingested DB").option("--db <path>", "SQLite DB path (overrides AGENT_LENS_DB / config db)").action((opts) => {
|
|
5452
5514
|
runMetrics(opts.db ? ["--db", opts.db] : []);
|
|
5453
5515
|
});
|
|
5454
|
-
cli.command("export <sessionId>", "Write a session to a shareable Markdown file (redacted by default)").option("--out <file>", "Write to this file (default: stdout)").option("--level <level>", "Redaction level: secrets (default) | structure").option("--no-redact", "Verbatim, UNREDACTED output (opt-out)").option("--db <path>", "SQLite DB path").action((sessionId, opts) => {
|
|
5455
|
-
const
|
|
5516
|
+
cli.command("export <sessionId>", "Write a session to a shareable Markdown file (redacted by default)").option("--out <file>", "Write to this file (default: stdout)").option("--level <level>", "Redaction level: secrets (default) | structure").option("--no-redact", "Verbatim, UNREDACTED output (opt-out)").option("--db <path>", "SQLite DB path (overrides AGENT_LENS_DB / config db)").action((sessionId, opts) => {
|
|
5517
|
+
const { path: dbPath } = resolveDbPath(opts.db);
|
|
5456
5518
|
if (!existsSync9(dbPath)) {
|
|
5457
5519
|
console.error(`agent-lens: db not found: ${dbPath} (run ingest first)`);
|
|
5458
5520
|
process.exit(1);
|
|
@@ -5478,6 +5540,39 @@ cli.command(
|
|
|
5478
5540
|
const hours = action === "install" ? parseHours(opts.times) : void 0;
|
|
5479
5541
|
runService(action, { cliEntry: fileURLToPath3(import.meta.url), hours, targets });
|
|
5480
5542
|
});
|
|
5543
|
+
cli.command("config", "Show the effective configuration (sources, paths, server) and where each value came from").action(() => {
|
|
5544
|
+
const repoRoot = findRepoRoot();
|
|
5545
|
+
const dataDir = resolveDataDir(repoRoot);
|
|
5546
|
+
const configFile = resolveConfigFile(repoRoot, dataDir);
|
|
5547
|
+
let server;
|
|
5548
|
+
try {
|
|
5549
|
+
server = resolveServerConfig();
|
|
5550
|
+
} catch (e) {
|
|
5551
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
5552
|
+
process.exit(1);
|
|
5553
|
+
}
|
|
5554
|
+
const { port, host, portOrigin, hostOrigin } = server;
|
|
5555
|
+
const { path: dbPath, origin: dbOrigin } = resolveDbPath();
|
|
5556
|
+
const archive = process.env.AGENT_LENS_ARCHIVE || join13(dataDir, "archive");
|
|
5557
|
+
const triageDb = process.env.AGENT_LENS_TRIAGE_DB || join13(dirname6(dbPath), "triage.db");
|
|
5558
|
+
const keepDays = process.env.AGENT_LENS_VERSIONS_KEEP_DAYS || "90";
|
|
5559
|
+
const keepOrigin = process.env.AGENT_LENS_VERSIONS_KEEP_DAYS ? "env" : "default";
|
|
5560
|
+
console.log("agent-lens config (precedence: flag > env > config file > default)\n");
|
|
5561
|
+
console.log("Paths");
|
|
5562
|
+
console.log(` config file ${configFile ?? "(none \u2014 using built-in default source)"}`);
|
|
5563
|
+
console.log(` data dir ${dataDir}${process.env.AGENT_LENS_DATA ? " [env]" : ""}`);
|
|
5564
|
+
console.log(` archive ${archive}${process.env.AGENT_LENS_ARCHIVE ? " [env]" : ""}`);
|
|
5565
|
+
console.log(` db ${dbPath} [${dbOrigin}]`);
|
|
5566
|
+
console.log(` triage db ${triageDb}${process.env.AGENT_LENS_TRIAGE_DB ? " [env]" : ""}`);
|
|
5567
|
+
console.log("\nServer");
|
|
5568
|
+
console.log(` host ${host} [${hostOrigin}]`);
|
|
5569
|
+
console.log(` port ${port} [${portOrigin}]`);
|
|
5570
|
+
console.log(` non-local bind ${process.env.AGENT_LENS_ALLOW_NONLOCAL ? "allowed (AGENT_LENS_ALLOW_NONLOCAL)" : "blocked (loopback only)"}`);
|
|
5571
|
+
console.log("\nRetention");
|
|
5572
|
+
console.log(` .versions keep ${keepDays} day(s) [${keepOrigin}]`);
|
|
5573
|
+
console.log("\nSources");
|
|
5574
|
+
for (const s of loadSources()) console.log(` ${s.label.padEnd(14)} ${s.configDir} (${s.agent})`);
|
|
5575
|
+
});
|
|
5481
5576
|
cli.help();
|
|
5482
5577
|
cli.version(version());
|
|
5483
5578
|
cli.parse();
|