From a509509192078be785f1b1d91153817c5ed059d7 Mon Sep 17 00:00:00 2001 From: Julian lechner Date: Wed, 16 Sep 2026 17:37:43 +0200 Subject: [PATCH] feat: add local session telemetry --- scripts/session-state.ps1 | 8 ++++++++ scripts/session-state.sh | 6 ++++++ scripts/telemetry.ps1 | 8 ++++++++ scripts/telemetry.sh | 10 ++++++++++ 4 files changed, 32 insertions(+) create mode 100644 scripts/session-state.ps1 create mode 100644 scripts/session-state.sh create mode 100644 scripts/telemetry.ps1 create mode 100644 scripts/telemetry.sh diff --git a/scripts/session-state.ps1 b/scripts/session-state.ps1 new file mode 100644 index 0000000..234ad3f --- /dev/null +++ b/scripts/session-state.ps1 @@ -0,0 +1,8 @@ +[CmdletBinding()] +param([string]$Goal,[string[]]$ChangedFiles=@(),[string[]]$Verified=@(),[string[]]$Pending=@(),[string[]]$ImportantFindings=@(),[switch]$Pointer) +$ErrorActionPreference = 'Stop' +$root = Split-Path $PSScriptRoot -Parent; $dir = Join-Path $root '.ai-session'; $path = Join-Path $dir 'state.json' +if ($Pointer) { if (Test-Path $path) { Write-Output 'Task state is available in .ai-session/state.json; read it only if needed.' }; exit 0 } +function Limit([string[]]$items) { @($items | Where-Object { $_ } | Select-Object -First 12 | ForEach-Object { if ($_.Length -gt 180) { $_.Substring(0,180) } else { $_ } }) } +New-Item $dir -ItemType Directory -Force | Out-Null +[ordered]@{ goal=if($Goal){$Goal.Substring(0,[Math]::Min(240,$Goal.Length))}else{''}; changedFiles=Limit $ChangedFiles; verified=Limit $Verified; pending=Limit $Pending; importantFindings=Limit $ImportantFindings; updatedAt=(Get-Date).ToUniversalTime().ToString('o') } | ConvertTo-Json -Depth 4 | Set-Content $path -Encoding UTF8 diff --git a/scripts/session-state.sh b/scripts/session-state.sh new file mode 100644 index 0000000..4bad3bb --- /dev/null +++ b/scripts/session-state.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd); dir="$root/.ai-session"; path="$dir/state.json" +if [ "${1:-}" = --pointer ]; then [ -f "$path" ] && printf 'Task state is available in .ai-session/state.json; read it only if needed.\n'; exit 0; fi +goal=${AI_TASK_GOAL:-}; goal=${goal:0:240}; goal_json=$(printf '%s' "$goal" | sed 's/[\\]/\\\\/g; s/"/\\"/g'); mkdir -p "$dir" +printf '{"goal":"%s","changedFiles":[],"verified":[],"pending":[],"importantFindings":[],"updatedAt":"%s"}\n' "$goal_json" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$path" diff --git a/scripts/telemetry.ps1 b/scripts/telemetry.ps1 new file mode 100644 index 0000000..266a52c --- /dev/null +++ b/scripts/telemetry.ps1 @@ -0,0 +1,8 @@ +[CmdletBinding()] +param([ValidateSet('record','summary','rotate')][string]$Action='record',[string]$Event,[string]$Agent,[string]$Role,[int]$DurationMs,[int]$ToolCalls,[string]$CommandClass,[int64]$Bytes,[int]$Count) +$ErrorActionPreference = 'Stop'; if ($env:AI_CONFIG_TELEMETRY -eq '0') { exit 0 } +$root = Split-Path $PSScriptRoot -Parent; $dir = Join-Path $root '.ai-session'; $path = Join-Path $dir 'telemetry.jsonl'; New-Item $dir -ItemType Directory -Force | Out-Null +if ($Action -eq 'rotate') { if (Test-Path $path) { Move-Item $path ($path + '.1') -Force }; exit 0 } +if ($Action -eq 'summary') { if (-not (Test-Path $path)) { Write-Output 'Telemetry: no events'; exit 0 }; $events=@(Get-Content $path | ForEach-Object { try { $_ | ConvertFrom-Json } catch {} }); $agents=@($events | Where-Object event -eq 'subagent-stop'); Write-Output ('Telemetry: {0} events | {1} subagents' -f $events.Count,$agents.Count); exit 0 } +if ([string]::IsNullOrWhiteSpace($Event)) { throw 'Event is required.' } +$record=[ordered]@{event=$Event;timestamp=(Get-Date).ToUniversalTime().ToString('o')}; foreach($pair in @(@('agent',$Agent),@('role',$Role),@('durationMs',$DurationMs),@('toolCalls',$ToolCalls),@('commandClass',$CommandClass),@('bytes',$Bytes),@('count',$Count))){if($pair[1]){$record[$pair[0]]=$pair[1]}}; ($record|ConvertTo-Json -Compress)|Add-Content $path; if((Get-Item $path).Length -gt 1048576){Move-Item $path ($path+'.1') -Force} diff --git a/scripts/telemetry.sh b/scripts/telemetry.sh new file mode 100644 index 0000000..e8f7ef0 --- /dev/null +++ b/scripts/telemetry.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +[ "${AI_CONFIG_TELEMETRY:-1}" = 0 ] && exit 0 +root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd); dir="$root/.ai-session"; path="$dir/telemetry.jsonl"; mkdir -p "$dir" +case "${1:-record}" in + rotate) [ -f "$path" ] && mv -f "$path" "$path.1"; exit 0;; + summary) [ -f "$path" ] || { printf 'Telemetry: no events\n'; exit 0; }; count=$(wc -l < "$path" | tr -d ' '); agents=$(grep -c '"event":"subagent-stop"' "$path" || true); printf 'Telemetry: %s events | %s subagents\n' "$count" "$agents"; exit 0;; + record) event=${2:?event required};; *) printf 'Unknown action: %s\n' "$1" >&2; exit 1;; +esac +printf '{"event":"%s","timestamp":"%s"}\n' "$event" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$path"; [ "$(wc -c < "$path")" -le 1048576 ] || mv -f "$path" "$path.1"