mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
feat(bash): add token-usage tracking to the bash port
Adds z_track_start/z_track_stop + z_record to zhelpers.sh and wires z_track_start into every command script. Each run now captures its own output volume (FIFO+tee, ANSI stripped), prints the '--- N lines / N chars / ~N tokens est. (Claude Code) ---' footer, and appends one JSONL row per top-level run in the same shape as the PowerShell tokens.jsonl. A nested-run guard keeps zrestart from double-counting its zkill/zstart children. Data dir precedence: $ZTOKENS_DATA, config ztokens.dataDir, sibling ../../ztokens/data, else ~/.ztokens/data. Docs + example config updated. Verified on WSL (isolated data dir): single run records correctly; nested zrestart produces one combined record, not three; est = round(chars/3.5).
This commit is contained in:
parent
cdeec77609
commit
09b98bc77b
@ -54,6 +54,30 @@ command argument:
|
||||
Flags use GNU style (`--port 3000`, `--detached`) instead of PowerShell style
|
||||
(`-Port`, `-Detached`). Detached dev servers log to `/tmp/zstart-<project>.log`.
|
||||
|
||||
## Usage tracking
|
||||
|
||||
Every run prints a footer with its own output volume:
|
||||
|
||||
```
|
||||
--- 1,048 lines / 69,009 chars / ~19,717 tokens est. (Claude Code) ---
|
||||
```
|
||||
|
||||
and (when `jq` is available) appends one JSON line per run to `tokens.jsonl`,
|
||||
so you can see how much infrastructure output you keep out of an AI agent's
|
||||
context over time. Fields: `ts, script, projects, lines, chars, est, model`
|
||||
(`est` ≈ `chars / 3.5`). Nested runs (the `zkill`/`zstart` inside `zrestart`)
|
||||
are counted once, not double.
|
||||
|
||||
Where it's written, first match wins:
|
||||
|
||||
1. `$ZTOKENS_DATA`
|
||||
2. `ztokens.dataDir` in `zconfig.json`
|
||||
3. the sibling `../ztokens/data` directory, if present
|
||||
4. `~/.ztokens/data` (created on first run)
|
||||
|
||||
Set `ZTOKENS_MODEL` to tag records with a specific model; it defaults to
|
||||
`est. chars/3.5`.
|
||||
|
||||
## Differences from the PowerShell versions
|
||||
|
||||
- `zsync <viteproject>` mirrors `dist/` with `rsync -a --delete` (robocopy /MIR equivalent).
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
set -uo pipefail
|
||||
_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$_HERE/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
|
||||
install=0; at_time="02:00"
|
||||
while [ $# -gt 0 ]; do
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require zip
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
set -uo pipefail
|
||||
_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$_HERE/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
|
||||
printf '\n'
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require ssh scp
|
||||
|
||||
|
||||
@ -16,6 +16,11 @@
|
||||
"oneDriveBackups": ""
|
||||
},
|
||||
|
||||
"ztokens": {
|
||||
"_comment": "Optional. Where each run's token-usage stats (tokens.jsonl) are recorded. Omit to use ~/.ztokens/data.",
|
||||
"dataDir": "/home/youruser/.ztokens/data"
|
||||
},
|
||||
|
||||
"projects": {
|
||||
"_comment": "Rename these keys to your own project names — the key IS the command argument: zstart pyapp, zdeploy viteapp, zbackup nextapp. Add as many projects as you like. Keys starting with _ are ignored.",
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require ssh scp zip curl jq
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require curl
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require curl ssh
|
||||
|
||||
|
||||
@ -237,3 +237,77 @@ kill_listeners() {
|
||||
done
|
||||
printf '%s' "$n"
|
||||
}
|
||||
|
||||
# ---- output tracking (ztokens) ----------------------------------------------
|
||||
# Mirrors the PowerShell Start-/Stop-ZTracking + tokens.jsonl feed: capture this
|
||||
# script's own output volume, print the "--- N lines / N chars / ~N tokens ---"
|
||||
# footer, and append one JSONL record per top-level run. Nested z-scripts (e.g.
|
||||
# zkill/zstart under zrestart) inherit the capture and do NOT double-count.
|
||||
# Call `z_track_start "$@"` once near the top; an EXIT trap covers every exit.
|
||||
z_track_start() {
|
||||
[ "${Z_TRACK_ACTIVE:-0}" = "1" ] && return # nested under another z-script
|
||||
command -v mktemp >/dev/null 2>&1 || return
|
||||
export Z_TRACK_ACTIVE=1
|
||||
Z_TRACK_SCRIPT="$(basename "$0")"
|
||||
Z_TRACK_ARGS="$*"
|
||||
Z_TRACK_FILE="$(mktemp "${TMPDIR:-/tmp}/ztrack.XXXXXX")" || { Z_TRACK_FILE=""; return; }
|
||||
Z_TRACK_FIFO="${Z_TRACK_FILE}.fifo"
|
||||
if ! mkfifo "$Z_TRACK_FIFO" 2>/dev/null; then rm -f "$Z_TRACK_FILE"; Z_TRACK_FILE=""; return; fi
|
||||
# tee copies the FIFO to the log file while still showing output on the terminal.
|
||||
tee "$Z_TRACK_FILE" < "$Z_TRACK_FIFO" &
|
||||
Z_TRACK_TEE=$!
|
||||
exec 3>&1 4>&2 >"$Z_TRACK_FIFO" 2>&1
|
||||
trap z_track_stop EXIT
|
||||
}
|
||||
|
||||
z_track_stop() {
|
||||
set +e # never let cleanup abort mid-way
|
||||
[ -n "${Z_TRACK_FILE:-}" ] || return
|
||||
exec 1>&3 2>&4 3>&- 4>&- # restore stdout/stderr, close the pipe
|
||||
[ -n "${Z_TRACK_TEE:-}" ] && wait "$Z_TRACK_TEE" 2>/dev/null
|
||||
rm -f "${Z_TRACK_FIFO:-}" 2>/dev/null
|
||||
|
||||
local esc plain lines chars tok
|
||||
esc=$'\033'
|
||||
plain="${Z_TRACK_FILE}.plain"
|
||||
sed "s/${esc}\[[0-9;]*m//g" "$Z_TRACK_FILE" > "$plain" 2>/dev/null || cp "$Z_TRACK_FILE" "$plain" 2>/dev/null
|
||||
lines="$(grep -cve '^[[:space:]]*$' "$plain" 2>/dev/null)"; [ -n "$lines" ] || lines=0
|
||||
chars="$(wc -m < "$plain" 2>/dev/null | tr -d ' ')"; [ -n "$chars" ] || chars=0
|
||||
tok="$(awk -v c="$chars" 'BEGIN{printf "%d", int(c/3.5 + 0.5)}')"
|
||||
|
||||
printf '\n%s--- %s lines / %s chars / ~%s tokens est. (Claude Code) ---%s\n' \
|
||||
"${C_GRAY:-}" "$(_z_commafy "$lines")" "$(_z_commafy "$chars")" "$(_z_commafy "$tok")" "${C_RESET:-}"
|
||||
|
||||
z_record "$lines" "$chars" "$tok"
|
||||
rm -f "$Z_TRACK_FILE" "$plain" 2>/dev/null
|
||||
Z_TRACK_FILE=""
|
||||
}
|
||||
|
||||
# Portable thousands separators (avoids locale-dependent printf %'d).
|
||||
_z_commafy() { printf '%s' "$1" | sed -E ':a;s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/;ta'; }
|
||||
|
||||
# Append a run to the ztokens JSONL store. Data dir precedence: $ZTOKENS_DATA,
|
||||
# then config "ztokens.dataDir", then the sibling ../../ztokens/data if present
|
||||
# (dev layout), else ~/.ztokens/data. No-op without jq. Model tag is
|
||||
# $ZTOKENS_MODEL or "est. chars/3.5".
|
||||
z_record() { # <lines> <chars> <est>
|
||||
command -v jq >/dev/null 2>&1 || return
|
||||
local lines="$1" chars="$2" est="$3" dir model projects
|
||||
dir="${ZTOKENS_DATA:-}"
|
||||
[ -z "$dir" ] && [ -f "$ZCONFIG" ] && dir="$(jq -r '.ztokens.dataDir // empty' "$ZCONFIG" 2>/dev/null)"
|
||||
if [ -z "$dir" ]; then
|
||||
if [ -d "$_ZDIR/../../ztokens/data" ]; then dir="$_ZDIR/../../ztokens/data"; else dir="$HOME/.ztokens/data"; fi
|
||||
fi
|
||||
mkdir -p "$dir" 2>/dev/null || return
|
||||
model="${ZTOKENS_MODEL:-est. chars/3.5}"
|
||||
projects=""
|
||||
[ -n "${Z_TRACK_ARGS:-}" ] && projects="$(printf '%s\n' $Z_TRACK_ARGS | grep -v '^-' | paste -sd',' - 2>/dev/null)"
|
||||
jq -cn \
|
||||
--arg ts "$(date +%Y-%m-%dT%H:%M:%S%z)" \
|
||||
--arg script "${Z_TRACK_SCRIPT%.*}" \
|
||||
--arg projects "$projects" \
|
||||
--argjson lines "${lines:-0}" --argjson chars "${chars:-0}" --argjson est "${est:-0}" \
|
||||
--arg model "$model" \
|
||||
'{ts:$ts,script:$script,projects:$projects,lines:$lines,chars:$chars,est:$est,model:$model}' \
|
||||
>> "$dir/tokens.jsonl" 2>/dev/null
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require lsof
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require ssh curl
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
set -uo pipefail
|
||||
_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$_HERE/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
|
||||
projects=(); port_override=0; kill_all=0; no_restart=0; detached=0; bind_host="127.0.0.1"
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require ssh
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
|
||||
projects=(); port_override=0; bind_host="127.0.0.1"; detached=0
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
set -uo pipefail
|
||||
_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$_HERE/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_require docker
|
||||
|
||||
build=0; attached=0; solo=0
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
z_require ssh
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
set -uo pipefail
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh"
|
||||
z_track_start "$@"
|
||||
z_need_config
|
||||
|
||||
projects=(); dest="${ZSYNC_DEST:-}"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user