agent-inspect 4.1.0 → 4.2.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add sessions and activity as first-class local concepts (v4.2).
8
+
9
+ - Derive session status, timing, last error, and retry counts on enriched `SessionSummary` (builds on v2.4 vocabulary; no timestamp-only causality).
10
+ - Add `buildActivitySummary` for windowed activity feeds.
11
+ - Expand CLI: `sessions latest`, `activity`, `show`, `handoffs`, `errors` (bare `sessions` list and `session <id>` unchanged).
12
+ - Optional SQLite index acceleration for session loading with automatic scan fallback when the index is absent, stale, or corrupt.
13
+ - Docs: CLI reference update.
14
+
3
15
  ## 4.1.0
4
16
 
5
17
  ### Minor Changes
package/docs/CLI.md CHANGED
@@ -42,7 +42,7 @@ Core commands:
42
42
  - `timeline` — chronological view of one run (local JSONL)
43
43
  - `stats` — local aggregate stats over a trace directory
44
44
  - `search` — deterministic local search over traces
45
- - `sessions` — list workflow sessions from trace metadata
45
+ - `sessions` — list workflow sessions; v4.2+ subcommands: `latest`, `activity`, `show`, `handoffs`, `errors`
46
46
  - `session` — inspect one session (handoffs, retries, optional timeline)
47
47
  - `what` — concise summary of a single run (local JSONL)
48
48
  - `report` — markdown or HTML inspection report for a single run
@@ -681,23 +681,34 @@ npx agent-inspect search --session sess-retry-001 --dir ./.agent-inspect
681
681
 
682
682
  ### 6.19 `sessions`
683
683
 
684
- List workflow sessions grouped from local trace metadata (`sessionId`, optional `groupId` correlation). Read-only; no network.
684
+ 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
685
 
686
686
  ```bash
687
- agent-inspect sessions [options]
687
+ agent-inspect sessions [options] # list sessions (default)
688
+ agent-inspect sessions latest [--json]
689
+ agent-inspect sessions activity [--since 7d] [--json]
690
+ agent-inspect sessions show <session-id> [--timeline] [--json]
691
+ agent-inspect sessions handoffs [--session <id>] [--json]
692
+ agent-inspect sessions errors [--since 7d] [--json]
688
693
  ```
689
694
 
690
- Options:
695
+ Shared options:
691
696
 
692
697
  - `--dir <path>`
693
698
  - `--correlate-group` — treat shared `groupId` as a synthetic session when `sessionId` is absent
694
- - `--json``SessionIndex` JSON (`sessions`, `unscopedRunIds`, `warnings`)
699
+ - `--stale-after <duration>` mark sessions stale after inactivity (e.g. `24h`, `7d`)
700
+ - `--json` — deterministic JSON output
701
+
702
+ `activity` and `errors` accept `--since <duration>` (e.g. `7d`, `24h`). Session summaries include derived `status`, `lastActivity`, `lastError`, and `retryCount` without changing trace files.
695
703
 
696
704
  Example:
697
705
 
698
706
  ```bash
699
707
  npx agent-inspect sessions --dir ./.agent-inspect
700
- npx agent-inspect sessions --json
708
+ npx agent-inspect sessions latest --json
709
+ npx agent-inspect sessions activity --since 7d
710
+ npx agent-inspect sessions handoffs --session sess-handoff-001
711
+ npx agent-inspect sessions errors --since 30d --json
701
712
  ```
702
713
 
703
714
  ### 6.20 `session`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-inspect",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Trace, check, and safely share TypeScript AI-agent runs locally — no account, no upload, metadata-only by default",
@@ -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 };
@@ -3094,14 +3340,21 @@ function buildSessionIndex(inputRuns, options = {}) {
3094
3340
  sessionId
3095
3341
  });
3096
3342
  }
3097
- return {
3098
- sessionId,
3099
- runIds,
3100
- groups,
3101
- handoffs,
3102
- retries,
3103
- criticalPath
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,6 @@ async function isAgentInspectTrace(filePath) {
3229
3482
  }
3230
3483
  }
3231
3484
 
3232
- export { Redactor, TraceDirectory, __commonJS, __require, __toESM, aggregateSessionCheckResults, applyProfileMetadataCaps, buildLocalExplanation, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, extractCorrelationMetadata, extractMetadata, filterMetasBySessionScope, filterTraces, formatDuration2 as formatDuration, formatTimestamp, getIndent, getTraceFilePath, isAgentInspectTrace, isPersistedInspectEvent, loadSessionRunRecords, loadTraceMetadataList, nanoid, parseDuration, parseDurationFilter, parseTraceJsonl, persistedInspectEventsToTraceEvents, renderErrorLine, renderRunWhat, renderStepLine, renderTimeline, renderTraceStats, resolveRedactionProfile, resolveTraceDir, searchTraces, source_default, truncateName, truncateStringForProfile, validateEvent };
3233
- //# sourceMappingURL=chunk-MT5G7JFO.mjs.map
3234
- //# sourceMappingURL=chunk-MT5G7JFO.mjs.map
3485
+ export { Redactor, TraceDirectory, __commonJS, __require, __toESM, aggregateSessionCheckResults, applyProfileMetadataCaps, buildActivitySummary, buildLocalExplanation, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, enrichSessionRunRecord, extractCorrelationMetadata, extractMetadata, filterMetasBySessionScope, filterTraces, formatDuration2 as formatDuration, formatTimestamp, getIndent, getTraceFilePath, isAgentInspectTrace, isPersistedInspectEvent, loadSessionRunRecords, loadTraceMetadataList, nanoid, parseDuration, parseDurationFilter, parseTraceJsonl, persistedInspectEventsToTraceEvents, renderActivitySummaryHuman, renderErrorLine, renderRunWhat, renderStepLine, renderTimeline, renderTraceStats, resolveRedactionProfile, resolveTraceDir, searchTraces, source_default, truncateName, truncateStringForProfile, validateEvent };
3486
+ //# sourceMappingURL=chunk-5VSPJEZ7.mjs.map
3487
+ //# sourceMappingURL=chunk-5VSPJEZ7.mjs.map