@swestash/agent-lens 0.15.0 → 0.16.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 +137 -38
- package/dist/agent-lens.js.map +1 -1
- package/package.json +1 -1
- package/web/404.html +1 -1
- package/web/assets/{AboutView-BD9cfwC2.js → AboutView-BExwxt7F.js} +1 -1
- package/web/assets/{Dashboard-fakmS_H4.js → Dashboard-DF8Xb9E1.js} +1 -1
- package/web/assets/{FileView-1MkgxkzO.js → FileView-hDF8bAaa.js} +1 -1
- package/web/assets/{FilesView-B6_w8jKK.js → FilesView-DW_bHt2e.js} +1 -1
- package/web/assets/{SecurityView-BX-IzE--.js → SecurityView-DPRI6HpG.js} +1 -1
- package/web/assets/{SessionView-DY5Xm26K.js → SessionView-eGmw43Bq.js} +1 -1
- package/web/assets/{SkillView-CnOhNPN4.js → SkillView-BdZwKqK6.js} +1 -1
- package/web/assets/{SkillsView-C76l9UYR.js → SkillsView-DUrXsvh_.js} +1 -1
- package/web/assets/{WorkflowView-Dq9JYCHd.js → WorkflowView-yNhKNcg9.js} +1 -1
- package/web/assets/{index-CcEbkJx7.js → index-BuG6Awf5.js} +1 -1
- package/web/assets/{index-CvMppG1z.js → index-CMT9aRT7.js} +2 -2
- package/web/assets/{jsonish-DMAKObPI.js → jsonish-DI8SpR-J.js} +1 -1
- package/web/assets/{theme-ByPiBqSS.js → theme-DiOdnv26.js} +1 -1
- package/web/assets/{useResetOn-BZWxJ_cM.js → useResetOn-BEUZVwM5.js} +1 -1
- package/web/index.html +1 -1
package/dist/agent-lens.js
CHANGED
|
@@ -812,9 +812,9 @@ CREATE INDEX IF NOT EXISTS idx_findings_category ON findings(category);
|
|
|
812
812
|
CREATE INDEX IF NOT EXISTS idx_findings_rule ON findings(rule_id);
|
|
813
813
|
CREATE INDEX IF NOT EXISTS idx_findings_tool_call ON findings(tool_call_id);
|
|
814
814
|
|
|
815
|
-
-- File modifications derived from tool calls (ADR-022). One row per (tool_call, file):
|
|
816
|
-
-- Edit/Write/NotebookEdit are 1:1
|
|
817
|
-
--
|
|
815
|
+
-- File modifications derived from tool calls (ADR-022). One row per (tool_call, file):
|
|
816
|
+
-- Edit/Write/NotebookEdit are 1:1; a Bash call can write several files, which the hash id already
|
|
817
|
+
-- accommodated without a schema break. Failed calls (status='error') are excluded
|
|
818
818
|
-- at derivation \u2014 they didn't change the file. Re-runnable like findings: incremental runs DELETE
|
|
819
819
|
-- the dirty sessions' rows and re-INSERT (delete-then-insert). Populated by ingest's
|
|
820
820
|
-- deriveFileChanges (filechanges.ts).
|
|
@@ -826,7 +826,7 @@ CREATE TABLE IF NOT EXISTS file_changes (
|
|
|
826
826
|
event_uuid TEXT, -- jump-to-transcript anchor (#ev-<uuid>)
|
|
827
827
|
project_id TEXT REFERENCES projects(id), -- from the session, for per-project grouping
|
|
828
828
|
file_path TEXT NOT NULL, -- normalized absolute path
|
|
829
|
-
tool_name TEXT NOT NULL, -- Edit | Write | NotebookEdit
|
|
829
|
+
tool_name TEXT NOT NULL, -- Edit | Write | NotebookEdit | Bash
|
|
830
830
|
lines_added INTEGER, -- newline-count delta (NULL when unknowable)
|
|
831
831
|
lines_removed INTEGER,
|
|
832
832
|
timestamp TEXT, -- ISO8601, from the tool call's event
|
|
@@ -3427,8 +3427,98 @@ function classifyErrors(db, dirty) {
|
|
|
3427
3427
|
// ../ingest/dist/filechanges.js
|
|
3428
3428
|
import { createHash as createHash3 } from "node:crypto";
|
|
3429
3429
|
import { posix as path2 } from "node:path";
|
|
3430
|
-
|
|
3431
|
-
|
|
3430
|
+
|
|
3431
|
+
// ../ingest/dist/shellwrites.js
|
|
3432
|
+
var TARGET = `"([^"]+)"|'([^']+)'|([^\\s;|&<>()]+)`;
|
|
3433
|
+
var REDIRECT = new RegExp(`(?:^|[\\s;|&(])\\d?>{1,2}\\s*(?:${TARGET})`, "g");
|
|
3434
|
+
var TEE = new RegExp(`(?:^|[\\s;|&(])tee\\s+(?:-a\\s+)?(?:${TARGET})`, "g");
|
|
3435
|
+
var SED_I = new RegExp(`(?:^|[\\s;|&(])sed\\s+(?:-[a-zA-Z]*i[a-zA-Z]*(?:\\.\\w+)?)\\s+(?:(?:-e\\s+)?(?:'[^']*'|"[^"]*"|\\S+)\\s+)+?(?:${TARGET})`, "g");
|
|
3436
|
+
var CD = new RegExp(`^\\s*cd\\s+(?:${TARGET})`);
|
|
3437
|
+
var HEREDOC = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g;
|
|
3438
|
+
var REDIRECT_BEFORE_HEREDOC = new RegExp(`\\d?>{1,2}\\s*(?:${TARGET})\\s*$`);
|
|
3439
|
+
function target(m, first) {
|
|
3440
|
+
return m[first] ?? m[first + 1] ?? m[first + 2] ?? null;
|
|
3441
|
+
}
|
|
3442
|
+
function usable(path3) {
|
|
3443
|
+
if (!path3)
|
|
3444
|
+
return false;
|
|
3445
|
+
if (/[$*?`~]/.test(path3))
|
|
3446
|
+
return false;
|
|
3447
|
+
if (path3.startsWith("&"))
|
|
3448
|
+
return false;
|
|
3449
|
+
if (path3 === "/dev/null" || path3.startsWith("/dev/"))
|
|
3450
|
+
return false;
|
|
3451
|
+
return true;
|
|
3452
|
+
}
|
|
3453
|
+
function bodyLines(body) {
|
|
3454
|
+
const trimmed = body.replace(/\n$/, "");
|
|
3455
|
+
return trimmed === "" ? 0 : trimmed.split("\n").length;
|
|
3456
|
+
}
|
|
3457
|
+
function stripHeredocs(command) {
|
|
3458
|
+
const writes = [];
|
|
3459
|
+
let scan = command;
|
|
3460
|
+
HEREDOC.lastIndex = 0;
|
|
3461
|
+
let m;
|
|
3462
|
+
while (m = HEREDOC.exec(scan)) {
|
|
3463
|
+
const delim = m[2];
|
|
3464
|
+
const openerEnd = scan.indexOf("\n", m.index);
|
|
3465
|
+
if (openerEnd === -1)
|
|
3466
|
+
break;
|
|
3467
|
+
const terminator = new RegExp(`^[ \\t]*${delim}[ \\t]*$`, "m");
|
|
3468
|
+
const rest = scan.slice(openerEnd + 1);
|
|
3469
|
+
const end = rest.search(terminator);
|
|
3470
|
+
const bodyEnd = end === -1 ? rest.length : end;
|
|
3471
|
+
const before = scan.slice(0, m.index);
|
|
3472
|
+
const red = before.match(REDIRECT_BEFORE_HEREDOC);
|
|
3473
|
+
if (red) {
|
|
3474
|
+
const p = target(red, 1);
|
|
3475
|
+
if (usable(p))
|
|
3476
|
+
writes.push({ at: red.index ?? m.index, write: { path: p, linesAdded: bodyLines(rest.slice(0, bodyEnd)) } });
|
|
3477
|
+
}
|
|
3478
|
+
const stripEnd = end === -1 ? scan.length : openerEnd + 1 + bodyEnd + delim.length;
|
|
3479
|
+
scan = scan.slice(0, m.index) + " ".repeat(stripEnd - m.index) + scan.slice(stripEnd);
|
|
3480
|
+
HEREDOC.lastIndex = stripEnd;
|
|
3481
|
+
}
|
|
3482
|
+
return { scan, writes };
|
|
3483
|
+
}
|
|
3484
|
+
function parseShellWrites(command) {
|
|
3485
|
+
if (typeof command !== "string" || !command)
|
|
3486
|
+
return { cwd: null, writes: [] };
|
|
3487
|
+
const cdMatch = command.match(CD);
|
|
3488
|
+
const cdPath = cdMatch ? target(cdMatch, 1) : null;
|
|
3489
|
+
const cwd = cdPath && cdPath.startsWith("/") && !/[$*?`~]/.test(cdPath) ? cdPath : null;
|
|
3490
|
+
const { scan, writes: found } = stripHeredocs(command);
|
|
3491
|
+
for (const [re, group] of [
|
|
3492
|
+
[REDIRECT, 1],
|
|
3493
|
+
[TEE, 1],
|
|
3494
|
+
[SED_I, 1]
|
|
3495
|
+
]) {
|
|
3496
|
+
re.lastIndex = 0;
|
|
3497
|
+
let m;
|
|
3498
|
+
while (m = re.exec(scan)) {
|
|
3499
|
+
const p = target(m, group);
|
|
3500
|
+
if (usable(p))
|
|
3501
|
+
found.push({ at: m.index, write: { path: p, linesAdded: null } });
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
3505
|
+
for (const entry of found) {
|
|
3506
|
+
const prev = byPath.get(entry.write.path);
|
|
3507
|
+
if (!prev) {
|
|
3508
|
+
byPath.set(entry.write.path, entry);
|
|
3509
|
+
continue;
|
|
3510
|
+
}
|
|
3511
|
+
byPath.set(entry.write.path, {
|
|
3512
|
+
at: Math.min(prev.at, entry.at),
|
|
3513
|
+
write: { path: entry.write.path, linesAdded: prev.write.linesAdded ?? entry.write.linesAdded }
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
return { cwd, writes: [...byPath.values()].sort((a, b) => a.at - b.at).map((e) => e.write) };
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
// ../ingest/dist/filechanges.js
|
|
3520
|
+
var FILECHANGES_VERSION = 2;
|
|
3521
|
+
var FILE_TOOLS = ["Edit", "Write", "NotebookEdit", "Bash"];
|
|
3432
3522
|
function fileChangeId(toolCallId, filePath) {
|
|
3433
3523
|
return createHash3("sha1").update(toolCallId).update("\0").update(filePath).digest("hex").slice(0, 16);
|
|
3434
3524
|
}
|
|
@@ -3489,31 +3579,40 @@ function deriveFileChanges(db, dirty) {
|
|
|
3489
3579
|
if (!input)
|
|
3490
3580
|
continue;
|
|
3491
3581
|
const p = proj.get(row.session_id);
|
|
3492
|
-
const
|
|
3493
|
-
if (
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
} else
|
|
3501
|
-
|
|
3582
|
+
const targets = [];
|
|
3583
|
+
if (row.tool_name === "Bash") {
|
|
3584
|
+
const { cwd, writes } = parseShellWrites(input.command);
|
|
3585
|
+
for (const w of writes) {
|
|
3586
|
+
const filePath = normalizeFilePath(w.path, cwd ?? p?.path ?? null);
|
|
3587
|
+
if (filePath)
|
|
3588
|
+
targets.push({ filePath, added: w.linesAdded, removed: null });
|
|
3589
|
+
}
|
|
3590
|
+
} else {
|
|
3591
|
+
const filePath = normalizeFilePath(input.file_path ?? input.notebook_path, p?.path ?? null);
|
|
3592
|
+
if (filePath) {
|
|
3593
|
+
targets.push({
|
|
3594
|
+
filePath,
|
|
3595
|
+
added: row.tool_name === "Edit" ? lineCount(input.new_string) : row.tool_name === "Write" ? lineCount(input.content) : null,
|
|
3596
|
+
removed: row.tool_name === "Edit" ? lineCount(input.old_string) : null
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
for (const t of targets) {
|
|
3601
|
+
insert.run({
|
|
3602
|
+
id: fileChangeId(row.id, t.filePath),
|
|
3603
|
+
tool_call_id: row.id,
|
|
3604
|
+
session_id: row.session_id,
|
|
3605
|
+
turn_id: row.turn_id,
|
|
3606
|
+
event_uuid: row.event_uuid,
|
|
3607
|
+
project_id: p?.id ?? null,
|
|
3608
|
+
file_path: t.filePath,
|
|
3609
|
+
tool_name: row.tool_name,
|
|
3610
|
+
lines_added: t.added,
|
|
3611
|
+
lines_removed: t.removed,
|
|
3612
|
+
timestamp: row.timestamp,
|
|
3613
|
+
derive_version: FILECHANGES_VERSION
|
|
3614
|
+
});
|
|
3502
3615
|
}
|
|
3503
|
-
insert.run({
|
|
3504
|
-
id: fileChangeId(row.id, filePath),
|
|
3505
|
-
tool_call_id: row.id,
|
|
3506
|
-
session_id: row.session_id,
|
|
3507
|
-
turn_id: row.turn_id,
|
|
3508
|
-
event_uuid: row.event_uuid,
|
|
3509
|
-
project_id: p?.id ?? null,
|
|
3510
|
-
file_path: filePath,
|
|
3511
|
-
tool_name: row.tool_name,
|
|
3512
|
-
lines_added: added,
|
|
3513
|
-
lines_removed: removed,
|
|
3514
|
-
timestamp: row.timestamp,
|
|
3515
|
-
derive_version: FILECHANGES_VERSION
|
|
3516
|
-
});
|
|
3517
3616
|
}
|
|
3518
3617
|
});
|
|
3519
3618
|
tx();
|
|
@@ -3585,15 +3684,15 @@ function canonicalizeProjects(db, opts = {}) {
|
|
|
3585
3684
|
const touched = /* @__PURE__ */ new Set();
|
|
3586
3685
|
transaction(db, () => {
|
|
3587
3686
|
for (const r of rows) {
|
|
3588
|
-
const
|
|
3589
|
-
if (
|
|
3687
|
+
const target2 = canon(r.path);
|
|
3688
|
+
if (target2 === strip(r.path))
|
|
3590
3689
|
continue;
|
|
3591
|
-
const targetId = byPath.get(
|
|
3690
|
+
const targetId = byPath.get(target2)?.id ?? projectId(r.agent_id, target2);
|
|
3592
3691
|
if (targetId === r.id)
|
|
3593
3692
|
continue;
|
|
3594
|
-
if (!byPath.has(
|
|
3595
|
-
upsertProject.run(targetId, r.agent_id,
|
|
3596
|
-
byPath.set(
|
|
3693
|
+
if (!byPath.has(target2)) {
|
|
3694
|
+
upsertProject.run(targetId, r.agent_id, target2);
|
|
3695
|
+
byPath.set(target2, { id: targetId, agent_id: r.agent_id });
|
|
3597
3696
|
}
|
|
3598
3697
|
repointSessions.run(targetId, r.id);
|
|
3599
3698
|
repointFileChanges.run(targetId, r.id);
|
|
@@ -6491,8 +6590,8 @@ cli.command("export <sessionId>", "Write a session to a shareable Markdown file
|
|
|
6491
6590
|
cli.command(
|
|
6492
6591
|
"service <action> [target]",
|
|
6493
6592
|
"Install/uninstall/status OS services \u2014 action: install|uninstall|status; target: collector|server|all (default all)"
|
|
6494
|
-
).option("--times <hours>", "Collector cadence: comma-separated hours 0-23 (default: 9,13,17,21)").action((action,
|
|
6495
|
-
const targets = parseTargets(
|
|
6593
|
+
).option("--times <hours>", "Collector cadence: comma-separated hours 0-23 (default: 9,13,17,21)").action((action, target2, opts) => {
|
|
6594
|
+
const targets = parseTargets(target2);
|
|
6496
6595
|
const hours = action === "install" ? parseHours(opts.times) : void 0;
|
|
6497
6596
|
runService(action, { cliEntry: fileURLToPath4(import.meta.url), hours, targets });
|
|
6498
6597
|
});
|