agent-inspect 4.1.0 → 4.3.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/CHANGELOG.md +18 -0
- package/docs/CLI.md +50 -6
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-MT5G7JFO.mjs → chunk-BS5LSKZ3.mjs} +451 -14
- package/packages/cli/dist/chunk-BS5LSKZ3.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +2662 -1561
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +2118 -1510
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-DUGEOAZ7.mjs → src-YFMPWEIS.mjs} +3 -3
- package/packages/cli/dist/{src-DUGEOAZ7.mjs.map → src-YFMPWEIS.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +461 -11
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +171 -1
- package/packages/core/dist/advanced.d.ts +171 -1
- package/packages/core/dist/advanced.mjs +450 -12
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/cli/dist/chunk-MT5G7JFO.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8a21bce: Add share-safe offline trace bundles (`agent-inspect bundle`) with automatic verify-safe, default share redaction profile, session/since targeting, and folder output for PR-ready evidence.
|
|
8
|
+
|
|
9
|
+
## 4.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Add sessions and activity as first-class local concepts (v4.2).
|
|
14
|
+
|
|
15
|
+
- Derive session status, timing, last error, and retry counts on enriched `SessionSummary` (builds on v2.4 vocabulary; no timestamp-only causality).
|
|
16
|
+
- Add `buildActivitySummary` for windowed activity feeds.
|
|
17
|
+
- Expand CLI: `sessions latest`, `activity`, `show`, `handoffs`, `errors` (bare `sessions` list and `session <id>` unchanged).
|
|
18
|
+
- Optional SQLite index acceleration for session loading with automatic scan fallback when the index is absent, stale, or corrupt.
|
|
19
|
+
- Docs: CLI reference update.
|
|
20
|
+
|
|
3
21
|
## 4.1.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/docs/CLI.md
CHANGED
|
@@ -37,12 +37,13 @@ Core commands:
|
|
|
37
37
|
- `scan` — best-effort local safety scan for trace capture risks
|
|
38
38
|
- `verify-safe` — best-effort local trace safety verification
|
|
39
39
|
- `artifacts` — create safe local CI trace artifact bundles and optional step summaries
|
|
40
|
+
- `bundle` — create share-safe offline trace bundles (redacted copies + verify-safe)
|
|
40
41
|
- `ci-summary` — summarize local reporter artifact manifests for CI
|
|
41
42
|
- `diff` — compare two manual traces (local, read-only)
|
|
42
43
|
- `timeline` — chronological view of one run (local JSONL)
|
|
43
44
|
- `stats` — local aggregate stats over a trace directory
|
|
44
45
|
- `search` — deterministic local search over traces
|
|
45
|
-
- `sessions` — list workflow sessions
|
|
46
|
+
- `sessions` — list workflow sessions; v4.2+ subcommands: `latest`, `activity`, `show`, `handoffs`, `errors`
|
|
46
47
|
- `session` — inspect one session (handoffs, retries, optional timeline)
|
|
47
48
|
- `what` — concise summary of a single run (local JSONL)
|
|
48
49
|
- `report` — markdown or HTML inspection report for a single run
|
|
@@ -681,23 +682,34 @@ npx agent-inspect search --session sess-retry-001 --dir ./.agent-inspect
|
|
|
681
682
|
|
|
682
683
|
### 6.19 `sessions`
|
|
683
684
|
|
|
684
|
-
|
|
685
|
+
Workflow sessions and activity from local trace metadata. v4.2 adds session status, activity summaries, and optional SQLite index acceleration (falls back to directory scan). Read-only; no network.
|
|
685
686
|
|
|
686
687
|
```bash
|
|
687
|
-
agent-inspect sessions [options]
|
|
688
|
+
agent-inspect sessions [options] # list sessions (default)
|
|
689
|
+
agent-inspect sessions latest [--json]
|
|
690
|
+
agent-inspect sessions activity [--since 7d] [--json]
|
|
691
|
+
agent-inspect sessions show <session-id> [--timeline] [--json]
|
|
692
|
+
agent-inspect sessions handoffs [--session <id>] [--json]
|
|
693
|
+
agent-inspect sessions errors [--since 7d] [--json]
|
|
688
694
|
```
|
|
689
695
|
|
|
690
|
-
|
|
696
|
+
Shared options:
|
|
691
697
|
|
|
692
698
|
- `--dir <path>`
|
|
693
699
|
- `--correlate-group` — treat shared `groupId` as a synthetic session when `sessionId` is absent
|
|
694
|
-
- `--
|
|
700
|
+
- `--stale-after <duration>` — mark sessions stale after inactivity (e.g. `24h`, `7d`)
|
|
701
|
+
- `--json` — deterministic JSON output
|
|
702
|
+
|
|
703
|
+
`activity` and `errors` accept `--since <duration>` (e.g. `7d`, `24h`). Session summaries include derived `status`, `lastActivity`, `lastError`, and `retryCount` without changing trace files.
|
|
695
704
|
|
|
696
705
|
Example:
|
|
697
706
|
|
|
698
707
|
```bash
|
|
699
708
|
npx agent-inspect sessions --dir ./.agent-inspect
|
|
700
|
-
npx agent-inspect sessions --json
|
|
709
|
+
npx agent-inspect sessions latest --json
|
|
710
|
+
npx agent-inspect sessions activity --since 7d
|
|
711
|
+
npx agent-inspect sessions handoffs --session sess-handoff-001
|
|
712
|
+
npx agent-inspect sessions errors --since 30d --json
|
|
701
713
|
```
|
|
702
714
|
|
|
703
715
|
### 6.20 `session`
|
|
@@ -849,6 +861,38 @@ agent-inspect index sqlite clean [--dir <path>] [--json]
|
|
|
849
861
|
|
|
850
862
|
If `@agent-inspect/index-sqlite` is not installed, these subcommands print a short install hint and exit non-zero.
|
|
851
863
|
|
|
864
|
+
### 6.24 `bundle`
|
|
865
|
+
|
|
866
|
+
Create a **share-safe offline trace bundle** as a local folder (v4.3+). Bundles are derived copies: original traces are read-only and never mutated. Automatic `verify-safe` runs before write; the command fails on `UNSAFE` unless `--allow-unsafe`. See [BUNDLES.md](BUNDLES.md).
|
|
867
|
+
|
|
868
|
+
```bash
|
|
869
|
+
agent-inspect bundle <run-id> [options]
|
|
870
|
+
agent-inspect bundle --session <session-id> [options]
|
|
871
|
+
agent-inspect bundle --since <duration> [options]
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
Options:
|
|
875
|
+
|
|
876
|
+
- `--dir <path>` — trace directory
|
|
877
|
+
- `--session <session-id>` — bundle all runs in a session
|
|
878
|
+
- `--since <duration>` — bundle runs with activity since a window (e.g. `24h`, `7d`)
|
|
879
|
+
- `--profile <profile>` — `local`, `share` (default), or `strict` redaction for exported copies
|
|
880
|
+
- `--out <path>` — output directory; `.zip` suffix is stripped (folder-first)
|
|
881
|
+
- `--allow-unsafe` — write bundle even when verify-safe reports UNSAFE
|
|
882
|
+
- `--json` — print deterministic JSON manifest
|
|
883
|
+
|
|
884
|
+
Output includes `trace.html`, `trace.jsonl`, `summary.md`, `metadata.json`, `check-results.json`, `redaction-report.json`, and `assets/runs/` mirrors for multi-run bundles.
|
|
885
|
+
|
|
886
|
+
Examples:
|
|
887
|
+
|
|
888
|
+
```bash
|
|
889
|
+
npx agent-inspect bundle minimal-success --dir fixtures/traces --out ./bundle-out
|
|
890
|
+
npx agent-inspect bundle --session sess-handoff-001 --dir ./.agent-inspect --profile strict
|
|
891
|
+
npx agent-inspect bundle --since 24h --dir ./.agent-inspect --json
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
Recipe: [shareable-bundle-basic](../examples/recipes/shareable-bundle-basic/README.md).
|
|
895
|
+
|
|
852
896
|
## 7. Optional TUI behavior
|
|
853
897
|
|
|
854
898
|
`view --tui` delegates to `@agent-inspect/tui` and requires an interactive terminal. If the package is not installed, the CLI prints a short install hint.
|
package/package.json
CHANGED
|
@@ -2714,6 +2714,95 @@ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
|
|
|
2714
2714
|
return metas;
|
|
2715
2715
|
}
|
|
2716
2716
|
|
|
2717
|
+
// packages/core/src/sessions/activity.ts
|
|
2718
|
+
function statusLine(session) {
|
|
2719
|
+
const name = session.workflowId ?? session.correlationId ?? session.sessionId;
|
|
2720
|
+
const status = session.status;
|
|
2721
|
+
if (session.lastError) {
|
|
2722
|
+
return `${name} session ${session.sessionId} failed at ${session.lastError.message}`;
|
|
2723
|
+
}
|
|
2724
|
+
if (session.observationSummary) {
|
|
2725
|
+
return `${name} session ${session.sessionId} ${status} with observation warning`;
|
|
2726
|
+
}
|
|
2727
|
+
return `${name} session ${session.sessionId} ${status}`;
|
|
2728
|
+
}
|
|
2729
|
+
function parseSinceMs(since, nowMs) {
|
|
2730
|
+
if (!since || since.trim() === "") return nowMs - 7 * 864e5;
|
|
2731
|
+
const trimmed = since.trim().toLowerCase();
|
|
2732
|
+
const match = /^(\d+)([smhd])$/.exec(trimmed);
|
|
2733
|
+
if (!match) return nowMs - 7 * 864e5;
|
|
2734
|
+
const amount = Number.parseInt(match[1], 10);
|
|
2735
|
+
const unit = match[2];
|
|
2736
|
+
const mult = unit === "s" ? 1e3 : unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5;
|
|
2737
|
+
return nowMs - amount * mult;
|
|
2738
|
+
}
|
|
2739
|
+
function isFailed(status) {
|
|
2740
|
+
return status === "error";
|
|
2741
|
+
}
|
|
2742
|
+
function isStale(status) {
|
|
2743
|
+
return status === "stale";
|
|
2744
|
+
}
|
|
2745
|
+
function guardrailWarnings(session) {
|
|
2746
|
+
const summary = session.checkSummary;
|
|
2747
|
+
if (!summary) return 0;
|
|
2748
|
+
return summary.warn;
|
|
2749
|
+
}
|
|
2750
|
+
function buildActivitySummary(index, options = {}) {
|
|
2751
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
2752
|
+
const sinceMs = parseSinceMs(options.since, nowMs);
|
|
2753
|
+
const sinceIso = new Date(sinceMs).toISOString();
|
|
2754
|
+
const limit = Number.isInteger(options.limit) && options.limit > 0 ? options.limit : 20;
|
|
2755
|
+
const inWindow = index.sessions.filter((session) => {
|
|
2756
|
+
const activityMs2 = Date.parse(session.lastActivity);
|
|
2757
|
+
return Number.isFinite(activityMs2) && activityMs2 >= sinceMs;
|
|
2758
|
+
});
|
|
2759
|
+
const entries = [...inWindow].sort((a, b) => Date.parse(b.lastActivity) - Date.parse(a.lastActivity)).slice(0, limit).map((session) => ({
|
|
2760
|
+
sessionId: session.sessionId,
|
|
2761
|
+
status: session.status,
|
|
2762
|
+
summary: statusLine(session),
|
|
2763
|
+
lastActivity: session.lastActivity,
|
|
2764
|
+
runCount: session.runIds.length
|
|
2765
|
+
}));
|
|
2766
|
+
let failed = 0;
|
|
2767
|
+
let stale = 0;
|
|
2768
|
+
let guardrailWarningTotal = 0;
|
|
2769
|
+
for (const session of inWindow) {
|
|
2770
|
+
if (isFailed(session.status)) failed += 1;
|
|
2771
|
+
if (isStale(session.status)) stale += 1;
|
|
2772
|
+
guardrailWarningTotal += guardrailWarnings(session);
|
|
2773
|
+
}
|
|
2774
|
+
return {
|
|
2775
|
+
since: sinceIso,
|
|
2776
|
+
sessions: inWindow.length,
|
|
2777
|
+
failed,
|
|
2778
|
+
stale,
|
|
2779
|
+
guardrailWarnings: guardrailWarningTotal,
|
|
2780
|
+
entries
|
|
2781
|
+
};
|
|
2782
|
+
}
|
|
2783
|
+
function renderActivitySummaryHuman(summary) {
|
|
2784
|
+
const lines = [];
|
|
2785
|
+
const todayStart = /* @__PURE__ */ new Date();
|
|
2786
|
+
todayStart.setHours(0, 0, 0, 0);
|
|
2787
|
+
const todayMs = todayStart.getTime();
|
|
2788
|
+
const today = summary.entries.filter(
|
|
2789
|
+
(entry) => Date.parse(entry.lastActivity) >= todayMs
|
|
2790
|
+
);
|
|
2791
|
+
if (today.length > 0) {
|
|
2792
|
+
lines.push("Today");
|
|
2793
|
+
for (const entry of today) {
|
|
2794
|
+
lines.push(` ${entry.summary}`);
|
|
2795
|
+
}
|
|
2796
|
+
lines.push("");
|
|
2797
|
+
}
|
|
2798
|
+
lines.push(`Since ${summary.since}`);
|
|
2799
|
+
lines.push(` ${summary.sessions} sessions`);
|
|
2800
|
+
lines.push(` ${summary.failed} failed`);
|
|
2801
|
+
lines.push(` ${summary.stale} stale`);
|
|
2802
|
+
lines.push(` ${summary.guardrailWarnings} guardrail warnings`);
|
|
2803
|
+
return lines.join("\n");
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2717
2806
|
// packages/core/src/sessions/load.ts
|
|
2718
2807
|
async function enrichSessionRunRecord(meta) {
|
|
2719
2808
|
let metadata;
|
|
@@ -2802,6 +2891,163 @@ function sessionKeyForRun(meta, options) {
|
|
|
2802
2891
|
return void 0;
|
|
2803
2892
|
}
|
|
2804
2893
|
|
|
2894
|
+
// packages/core/src/sessions/status.ts
|
|
2895
|
+
var DEFAULT_STALE_THRESHOLD_MS = 864e5;
|
|
2896
|
+
var EXPLICIT_STATUS_PRIORITY = {
|
|
2897
|
+
error: 5,
|
|
2898
|
+
waiting_input: 4,
|
|
2899
|
+
idle: 3,
|
|
2900
|
+
stale: 2,
|
|
2901
|
+
completed: 1
|
|
2902
|
+
};
|
|
2903
|
+
var EXPLICIT_SESSION_STATUSES = /* @__PURE__ */ new Set([
|
|
2904
|
+
"running",
|
|
2905
|
+
"waiting_input",
|
|
2906
|
+
"idle",
|
|
2907
|
+
"completed",
|
|
2908
|
+
"error",
|
|
2909
|
+
"stale",
|
|
2910
|
+
"unknown"
|
|
2911
|
+
]);
|
|
2912
|
+
function isExplicitSessionStatus(value) {
|
|
2913
|
+
return typeof value === "string" && EXPLICIT_SESSION_STATUSES.has(value);
|
|
2914
|
+
}
|
|
2915
|
+
function activityMs(run) {
|
|
2916
|
+
return run.endedAt ?? run.startedAt ?? 0;
|
|
2917
|
+
}
|
|
2918
|
+
function latestActivityMs(runs) {
|
|
2919
|
+
let latest = 0;
|
|
2920
|
+
for (const run of runs) {
|
|
2921
|
+
const ms = activityMs(run);
|
|
2922
|
+
if (ms > latest) latest = ms;
|
|
2923
|
+
}
|
|
2924
|
+
return latest;
|
|
2925
|
+
}
|
|
2926
|
+
function earliestStart(runs) {
|
|
2927
|
+
let earliest;
|
|
2928
|
+
for (const run of runs) {
|
|
2929
|
+
if (run.startedAt === void 0) continue;
|
|
2930
|
+
if (earliest === void 0 || run.startedAt < earliest) {
|
|
2931
|
+
earliest = run.startedAt;
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
return earliest;
|
|
2935
|
+
}
|
|
2936
|
+
function latestEndWhenAllEnded(runs) {
|
|
2937
|
+
if (runs.length === 0) return void 0;
|
|
2938
|
+
let latest;
|
|
2939
|
+
for (const run of runs) {
|
|
2940
|
+
if (run.endedAt === void 0) return void 0;
|
|
2941
|
+
if (latest === void 0 || run.endedAt > latest) latest = run.endedAt;
|
|
2942
|
+
}
|
|
2943
|
+
return latest;
|
|
2944
|
+
}
|
|
2945
|
+
function pickExplicitStatus(runs) {
|
|
2946
|
+
let best;
|
|
2947
|
+
let bestPriority = 0;
|
|
2948
|
+
for (const run of runs) {
|
|
2949
|
+
const raw = run.metadata?.sessionStatus;
|
|
2950
|
+
if (!isExplicitSessionStatus(raw)) continue;
|
|
2951
|
+
const priority = EXPLICIT_STATUS_PRIORITY[raw] ?? 0;
|
|
2952
|
+
if (priority > bestPriority) {
|
|
2953
|
+
bestPriority = priority;
|
|
2954
|
+
best = raw;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
return best;
|
|
2958
|
+
}
|
|
2959
|
+
function deriveLastError(runs) {
|
|
2960
|
+
const errorRuns = runs.filter((run) => run.status === "error").sort((a, b) => activityMs(b) - activityMs(a));
|
|
2961
|
+
const latest = errorRuns[0];
|
|
2962
|
+
if (!latest) return void 0;
|
|
2963
|
+
const meta = latest.metadata ?? {};
|
|
2964
|
+
const message = typeof meta.errorMessage === "string" && meta.errorMessage.trim() !== "" ? meta.errorMessage.trim() : latest.name ?? latest.runId;
|
|
2965
|
+
const code = typeof meta.errorCode === "string" && meta.errorCode.trim() !== "" ? meta.errorCode.trim() : void 0;
|
|
2966
|
+
return { runId: latest.runId, message, code };
|
|
2967
|
+
}
|
|
2968
|
+
function deriveCheckSummary(runs) {
|
|
2969
|
+
let pass = 0;
|
|
2970
|
+
let fail = 0;
|
|
2971
|
+
let warn2 = 0;
|
|
2972
|
+
let found = false;
|
|
2973
|
+
for (const run of runs) {
|
|
2974
|
+
const summary = run.metadata?.checkSummary;
|
|
2975
|
+
if (!summary || typeof summary !== "object") continue;
|
|
2976
|
+
const record = summary;
|
|
2977
|
+
if (typeof record.pass === "number") {
|
|
2978
|
+
pass += record.pass;
|
|
2979
|
+
found = true;
|
|
2980
|
+
}
|
|
2981
|
+
if (typeof record.fail === "number") {
|
|
2982
|
+
fail += record.fail;
|
|
2983
|
+
found = true;
|
|
2984
|
+
}
|
|
2985
|
+
if (typeof record.warn === "number") {
|
|
2986
|
+
warn2 += record.warn;
|
|
2987
|
+
found = true;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
return found ? { pass, fail, warn: warn2 } : void 0;
|
|
2991
|
+
}
|
|
2992
|
+
function deriveObservationSummary(runs) {
|
|
2993
|
+
for (const run of [...runs].sort((a, b) => activityMs(b) - activityMs(a))) {
|
|
2994
|
+
const value = run.metadata?.observationSummary;
|
|
2995
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
2996
|
+
return value.trim();
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return void 0;
|
|
3000
|
+
}
|
|
3001
|
+
function deriveSessionStatus(runs, options = {}) {
|
|
3002
|
+
if (runs.length === 0) return "unknown";
|
|
3003
|
+
if (runs.some((run) => run.status === "running")) return "running";
|
|
3004
|
+
const explicit = pickExplicitStatus(runs);
|
|
3005
|
+
if (explicit && explicit !== "running") return explicit;
|
|
3006
|
+
if (runs.some((run) => run.status === "error")) return "error";
|
|
3007
|
+
if (runs.every((run) => run.status === "success")) return "completed";
|
|
3008
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
3009
|
+
const staleThresholdMs = options.staleThresholdMs ?? DEFAULT_STALE_THRESHOLD_MS;
|
|
3010
|
+
const lastMs = latestActivityMs(runs);
|
|
3011
|
+
if (lastMs > 0 && nowMs - lastMs > staleThresholdMs) return "stale";
|
|
3012
|
+
return "unknown";
|
|
3013
|
+
}
|
|
3014
|
+
function enrichSessionSummary(summary, runs, options = {}) {
|
|
3015
|
+
const sessionRuns = runs.filter((run) => summary.runIds.includes(run.runId)).sort((a, b) => a.runId.localeCompare(b.runId));
|
|
3016
|
+
const startedAt = earliestStart(sessionRuns);
|
|
3017
|
+
const endedAt = latestEndWhenAllEnded(sessionRuns);
|
|
3018
|
+
const durationMs = startedAt !== void 0 && endedAt !== void 0 ? endedAt - startedAt : void 0;
|
|
3019
|
+
let correlationId;
|
|
3020
|
+
let jobId;
|
|
3021
|
+
let workflowId;
|
|
3022
|
+
for (const run of sessionRuns) {
|
|
3023
|
+
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
3024
|
+
if (!correlationId && meta?.correlationId) correlationId = meta.correlationId;
|
|
3025
|
+
if (!jobId && meta?.jobId) jobId = meta.jobId;
|
|
3026
|
+
if (!workflowId && meta?.workflowName) workflowId = meta.workflowName;
|
|
3027
|
+
else if (!workflowId && meta?.workflowStep) workflowId = meta.workflowStep;
|
|
3028
|
+
}
|
|
3029
|
+
const lastMs = latestActivityMs(sessionRuns);
|
|
3030
|
+
const lastActivity = lastMs > 0 ? new Date(lastMs).toISOString() : (/* @__PURE__ */ new Date(0)).toISOString();
|
|
3031
|
+
const retryCount = summary.retries.filter(
|
|
3032
|
+
(retry) => retry.retryOf !== void 0 || (retry.attempt ?? 0) > 1
|
|
3033
|
+
).length;
|
|
3034
|
+
return {
|
|
3035
|
+
...summary,
|
|
3036
|
+
status: deriveSessionStatus(sessionRuns, options),
|
|
3037
|
+
startedAt,
|
|
3038
|
+
endedAt,
|
|
3039
|
+
durationMs,
|
|
3040
|
+
correlationId,
|
|
3041
|
+
jobId,
|
|
3042
|
+
workflowId,
|
|
3043
|
+
lastError: deriveLastError(sessionRuns),
|
|
3044
|
+
lastActivity,
|
|
3045
|
+
retryCount,
|
|
3046
|
+
observationSummary: deriveObservationSummary(sessionRuns),
|
|
3047
|
+
checkSummary: deriveCheckSummary(sessionRuns)
|
|
3048
|
+
};
|
|
3049
|
+
}
|
|
3050
|
+
|
|
2805
3051
|
// packages/core/src/sessions/checks.ts
|
|
2806
3052
|
function emptySummary() {
|
|
2807
3053
|
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
@@ -3022,12 +3268,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3022
3268
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3023
3269
|
);
|
|
3024
3270
|
const ordered = [...runs].sort(compareRuns);
|
|
3025
|
-
const
|
|
3271
|
+
const path6 = [];
|
|
3026
3272
|
const visited = /* @__PURE__ */ new Set();
|
|
3027
3273
|
const pushRun = (run, confidence, source) => {
|
|
3028
3274
|
if (visited.has(run.runId)) return;
|
|
3029
3275
|
visited.add(run.runId);
|
|
3030
|
-
|
|
3276
|
+
path6.push({
|
|
3031
3277
|
runId: run.runId,
|
|
3032
3278
|
name: run.name,
|
|
3033
3279
|
startedAt: run.startedAt,
|
|
@@ -3052,7 +3298,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
3052
3298
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3053
3299
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3054
3300
|
}
|
|
3055
|
-
return
|
|
3301
|
+
return path6;
|
|
3056
3302
|
}
|
|
3057
3303
|
function metaRunIdMatches(run, token, runById) {
|
|
3058
3304
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -3094,14 +3340,21 @@ function buildSessionIndex(inputRuns, options = {}) {
|
|
|
3094
3340
|
sessionId
|
|
3095
3341
|
});
|
|
3096
3342
|
}
|
|
3097
|
-
return
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3343
|
+
return enrichSessionSummary(
|
|
3344
|
+
{
|
|
3345
|
+
sessionId,
|
|
3346
|
+
runIds,
|
|
3347
|
+
groups,
|
|
3348
|
+
handoffs,
|
|
3349
|
+
retries,
|
|
3350
|
+
criticalPath
|
|
3351
|
+
},
|
|
3352
|
+
runs,
|
|
3353
|
+
{
|
|
3354
|
+
nowMs: options.nowMs,
|
|
3355
|
+
staleThresholdMs: options.staleThresholdMs
|
|
3356
|
+
}
|
|
3357
|
+
);
|
|
3105
3358
|
});
|
|
3106
3359
|
if (sessions.length === 0 && runs.length > 0) {
|
|
3107
3360
|
warnings.push({
|
|
@@ -3229,6 +3482,190 @@ async function isAgentInspectTrace(filePath) {
|
|
|
3229
3482
|
}
|
|
3230
3483
|
}
|
|
3231
3484
|
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3485
|
+
// packages/core/src/bundle/resolve.ts
|
|
3486
|
+
function parseSinceCutoff(since) {
|
|
3487
|
+
const trimmed = since.trim();
|
|
3488
|
+
if (trimmed === "") {
|
|
3489
|
+
throw new Error("--since requires a non-empty duration (e.g. 24h, 7d).");
|
|
3490
|
+
}
|
|
3491
|
+
return Date.now() - parseDuration(trimmed);
|
|
3492
|
+
}
|
|
3493
|
+
function runActivityMs(run) {
|
|
3494
|
+
if (run.startedAt !== void 0 && Number.isFinite(run.startedAt)) return run.startedAt;
|
|
3495
|
+
if (run.endedAt !== void 0 && Number.isFinite(run.endedAt)) return run.endedAt;
|
|
3496
|
+
return void 0;
|
|
3497
|
+
}
|
|
3498
|
+
function runsInSinceWindow(runs, since) {
|
|
3499
|
+
const cutoff = parseSinceCutoff(since);
|
|
3500
|
+
const ids = [];
|
|
3501
|
+
for (const run of runs) {
|
|
3502
|
+
const activity = runActivityMs(run);
|
|
3503
|
+
if (activity !== void 0 && activity >= cutoff) {
|
|
3504
|
+
ids.push(run.runId);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
return ids.sort((a, b) => a.localeCompare(b));
|
|
3508
|
+
}
|
|
3509
|
+
function findSession(index, sessionId) {
|
|
3510
|
+
return index.sessions.find((session) => session.sessionId === sessionId);
|
|
3511
|
+
}
|
|
3512
|
+
function resolveBundleRunIds(index, runs, options) {
|
|
3513
|
+
const runId = options.runId?.trim();
|
|
3514
|
+
const sessionId = options.sessionId?.trim();
|
|
3515
|
+
const since = options.since?.trim();
|
|
3516
|
+
const modes = [runId ? 1 : 0, sessionId ? 1 : 0, since ? 1 : 0].reduce((a, b) => a + b, 0);
|
|
3517
|
+
if (modes === 0) {
|
|
3518
|
+
throw new Error(
|
|
3519
|
+
"bundle requires a run id, --session <sessionId>, or --since <duration>."
|
|
3520
|
+
);
|
|
3521
|
+
}
|
|
3522
|
+
if (modes > 1) {
|
|
3523
|
+
throw new Error(
|
|
3524
|
+
"bundle accepts only one target: a run id, --session, or --since (not combined)."
|
|
3525
|
+
);
|
|
3526
|
+
}
|
|
3527
|
+
if (runId) {
|
|
3528
|
+
const known = runs.some((run) => run.runId === runId);
|
|
3529
|
+
if (!known) {
|
|
3530
|
+
throw new Error(`Run "${runId}" was not found in the trace directory.`);
|
|
3531
|
+
}
|
|
3532
|
+
return { runIds: [runId] };
|
|
3533
|
+
}
|
|
3534
|
+
if (sessionId) {
|
|
3535
|
+
const session = findSession(index, sessionId);
|
|
3536
|
+
if (!session) {
|
|
3537
|
+
throw new Error(`Session "${sessionId}" was not found.`);
|
|
3538
|
+
}
|
|
3539
|
+
if (session.runIds.length === 0) {
|
|
3540
|
+
throw new Error(`Session "${sessionId}" has no runs to bundle.`);
|
|
3541
|
+
}
|
|
3542
|
+
return {
|
|
3543
|
+
runIds: [...session.runIds].sort((a, b) => a.localeCompare(b)),
|
|
3544
|
+
sessionId
|
|
3545
|
+
};
|
|
3546
|
+
}
|
|
3547
|
+
const runIds = runsInSinceWindow(runs, since);
|
|
3548
|
+
if (runIds.length === 0) {
|
|
3549
|
+
throw new Error(`No runs matched --since ${since}.`);
|
|
3550
|
+
}
|
|
3551
|
+
return { runIds, since };
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
// packages/core/src/bundle/safety-status.ts
|
|
3555
|
+
function aggregateBundleSafeStatus(statuses) {
|
|
3556
|
+
if (statuses.length === 0) return "UNKNOWN";
|
|
3557
|
+
if (statuses.some((status) => status === "UNSAFE")) return "UNSAFE";
|
|
3558
|
+
if (statuses.some((status) => status === "UNKNOWN")) return "UNKNOWN";
|
|
3559
|
+
if (statuses.some((status) => status === "SAFE WITH WARNINGS")) return "SAFE WITH WARNINGS";
|
|
3560
|
+
return "SAFE";
|
|
3561
|
+
}
|
|
3562
|
+
function toMetadataSafeStatus(status) {
|
|
3563
|
+
if (status === "SAFE WITH WARNINGS") return "SAFE_WITH_WARNINGS";
|
|
3564
|
+
return status;
|
|
3565
|
+
}
|
|
3566
|
+
function bundleFailsOnSafety(status, allowUnsafe) {
|
|
3567
|
+
if (allowUnsafe) return false;
|
|
3568
|
+
return status === "UNSAFE" || status === "UNKNOWN";
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3571
|
+
// packages/core/src/bundle/manifest.ts
|
|
3572
|
+
var BUNDLE_NOTE = "Generated locally by AgentInspect. Bundles are derived copies for review \u2014 not compliance or security certification. Review before sharing.";
|
|
3573
|
+
var PLACEHOLDER_NOTE = "No eval or performance artifacts were requested for this bundle.";
|
|
3574
|
+
function buildBundleMetadata(parts) {
|
|
3575
|
+
const aggregate = aggregateBundleSafeStatus(
|
|
3576
|
+
parts.checks.runs.map((run) => run.status)
|
|
3577
|
+
);
|
|
3578
|
+
return {
|
|
3579
|
+
createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3580
|
+
agentInspectVersion: parts.agentInspectVersion,
|
|
3581
|
+
redactionProfile: parts.profile,
|
|
3582
|
+
sourceTraceCount: parts.resolve.runIds.length,
|
|
3583
|
+
runIds: [...parts.resolve.runIds],
|
|
3584
|
+
safeStatus: toMetadataSafeStatus(aggregate),
|
|
3585
|
+
files: [...parts.files].sort((a, b) => a.localeCompare(b)),
|
|
3586
|
+
note: BUNDLE_NOTE,
|
|
3587
|
+
...parts.resolve.sessionId !== void 0 ? { sessionId: parts.resolve.sessionId } : {},
|
|
3588
|
+
...parts.resolve.since !== void 0 ? { since: parts.resolve.since } : {}
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3591
|
+
function buildPlaceholderArtifact() {
|
|
3592
|
+
return {
|
|
3593
|
+
status: "not_requested",
|
|
3594
|
+
note: PLACEHOLDER_NOTE
|
|
3595
|
+
};
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
// packages/core/src/bundle/summary.ts
|
|
3599
|
+
function markdownTable(rows) {
|
|
3600
|
+
const lines = ["| Field | Value |", "| --- | --- |"];
|
|
3601
|
+
for (const [key, value] of rows) {
|
|
3602
|
+
lines.push(`| ${key} | ${value ?? "unknown"} |`);
|
|
3603
|
+
}
|
|
3604
|
+
return lines.join("\n");
|
|
3605
|
+
}
|
|
3606
|
+
function buildBundleSummaryMarkdown(parts) {
|
|
3607
|
+
const { metadata, checks, redaction } = parts;
|
|
3608
|
+
const lines = [
|
|
3609
|
+
"# AgentInspect trace bundle",
|
|
3610
|
+
"",
|
|
3611
|
+
metadata.note,
|
|
3612
|
+
"",
|
|
3613
|
+
"## Overview",
|
|
3614
|
+
"",
|
|
3615
|
+
markdownTable([
|
|
3616
|
+
["Created", metadata.createdAt],
|
|
3617
|
+
["AgentInspect", metadata.agentInspectVersion],
|
|
3618
|
+
["Redaction profile", metadata.redactionProfile],
|
|
3619
|
+
["Safe status", metadata.safeStatus],
|
|
3620
|
+
["Source traces", metadata.sourceTraceCount],
|
|
3621
|
+
["Runs", metadata.runIds.join(", ")],
|
|
3622
|
+
...metadata.sessionId ? [["Session", metadata.sessionId]] : [],
|
|
3623
|
+
...metadata.since ? [["Since", metadata.since]] : []
|
|
3624
|
+
]),
|
|
3625
|
+
"",
|
|
3626
|
+
"## Safety checks",
|
|
3627
|
+
"",
|
|
3628
|
+
`Aggregate: **${checks.aggregateStatus}**`,
|
|
3629
|
+
""
|
|
3630
|
+
];
|
|
3631
|
+
for (const run of checks.runs) {
|
|
3632
|
+
lines.push(
|
|
3633
|
+
`- \`${run.runId}\`: ${run.status} (${run.findings} finding(s), ${run.errors} error(s), ${run.warnings} warning(s))`
|
|
3634
|
+
);
|
|
3635
|
+
}
|
|
3636
|
+
lines.push("", "## Redaction", "", `Total findings: ${redaction.totalFindings}`, "");
|
|
3637
|
+
for (const run of redaction.runs) {
|
|
3638
|
+
const detectors = run.detectors.length > 0 ? run.detectors.join(", ") : "none";
|
|
3639
|
+
lines.push(`- \`${run.runId}\`: ${run.findings} finding(s); detectors: ${detectors}`);
|
|
3640
|
+
}
|
|
3641
|
+
lines.push(
|
|
3642
|
+
"",
|
|
3643
|
+
"## Files",
|
|
3644
|
+
"",
|
|
3645
|
+
...metadata.files.map((file) => `- \`${file}\``),
|
|
3646
|
+
"",
|
|
3647
|
+
"_Review every generated artifact before sharing outside your team._",
|
|
3648
|
+
""
|
|
3649
|
+
);
|
|
3650
|
+
return lines.join("\n");
|
|
3651
|
+
}
|
|
3652
|
+
function normalizeBundleOutputPath(out) {
|
|
3653
|
+
const trimmed = out.trim();
|
|
3654
|
+
if (trimmed === "") {
|
|
3655
|
+
throw new Error("--out requires a non-empty path.");
|
|
3656
|
+
}
|
|
3657
|
+
const resolved = path.resolve(trimmed);
|
|
3658
|
+
if (resolved.toLowerCase().endsWith(".zip")) {
|
|
3659
|
+
return resolved.slice(0, -4);
|
|
3660
|
+
}
|
|
3661
|
+
return resolved;
|
|
3662
|
+
}
|
|
3663
|
+
function defaultBundleOutputPath(runIds) {
|
|
3664
|
+
const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
|
|
3665
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3666
|
+
return path.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
export { Redactor, TraceDirectory, __commonJS, __require, __toESM, aggregateBundleSafeStatus, aggregateSessionCheckResults, applyProfileMetadataCaps, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildLocalExplanation, buildPlaceholderArtifact, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, bundleFailsOnSafety, defaultBundleOutputPath, enrichSessionRunRecord, extractCorrelationMetadata, extractMetadata, filterMetasBySessionScope, filterTraces, formatDuration2 as formatDuration, formatTimestamp, getIndent, getTraceFilePath, isAgentInspectTrace, isPersistedInspectEvent, loadSessionRunRecords, loadTraceMetadataList, nanoid, normalizeBundleOutputPath, parseDuration, parseDurationFilter, parseTraceJsonl, persistedInspectEventsToTraceEvents, renderActivitySummaryHuman, renderErrorLine, renderRunWhat, renderStepLine, renderTimeline, renderTraceStats, resolveBundleRunIds, resolveRedactionProfile, resolveTraceDir, searchTraces, source_default, truncateName, truncateStringForProfile, validateEvent };
|
|
3670
|
+
//# sourceMappingURL=chunk-BS5LSKZ3.mjs.map
|
|
3671
|
+
//# sourceMappingURL=chunk-BS5LSKZ3.mjs.map
|