clawmonitor 1.0.1 → 1.1.2
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/README.md +10 -40
- package/README.zh-CN.md +22 -51
- package/README.zh-TW.md +21 -50
- package/bin/clawmonitor.js +733 -0
- package/package.json +4 -6
- package/bin/clawmonitor.sh +0 -466
package/package.json
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawmonitor",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Real-time OpenClaw tool call monitor
|
|
5
|
-
"bin":
|
|
6
|
-
"clawmonitor": "./bin/clawmonitor.sh"
|
|
7
|
-
},
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "Real-time OpenClaw tool call monitor with TUI, JSON highlighting, and zero dependencies",
|
|
5
|
+
"bin": "./bin/clawmonitor.js",
|
|
8
6
|
"scripts": {
|
|
9
|
-
"test": "
|
|
7
|
+
"test": "node --check bin/clawmonitor.js"
|
|
10
8
|
},
|
|
11
9
|
"keywords": [
|
|
12
10
|
"openclaw",
|
package/bin/clawmonitor.sh
DELETED
|
@@ -1,466 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# clawmonitor — Real-time OpenClaw tool call monitor
|
|
3
|
-
#
|
|
4
|
-
# Usage:
|
|
5
|
-
# clawmonitor # Default: last 30 min sessions + 10 history
|
|
6
|
-
# clawmonitor --all # Monitor all sessions
|
|
7
|
-
# clawmonitor --compact # Compact output
|
|
8
|
-
# clawmonitor --history N # Show N recent tool calls
|
|
9
|
-
#
|
|
10
|
-
# npx clawmonitor # Run without installing
|
|
11
|
-
|
|
12
|
-
set -euo pipefail
|
|
13
|
-
|
|
14
|
-
# === Platform detection ===
|
|
15
|
-
OS="$(uname -s 2>/dev/null || echo "unknown")"
|
|
16
|
-
ARCH="$(uname -m 2>/dev/null || echo "unknown")"
|
|
17
|
-
|
|
18
|
-
IS_WINDOWS=false
|
|
19
|
-
if [[ "$OS" == "MINGW"* || "$OS" == "MSYS"* || "$OS" == "CYGWIN"* ]]; then
|
|
20
|
-
IS_WINDOWS=true
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
# === Detect OpenClaw data directory ===
|
|
24
|
-
if [[ -n "${OPENCLAW_HOME:-}" ]]; then
|
|
25
|
-
AGENTS_DIR="$OPENCLAW_HOME/agents"
|
|
26
|
-
elif [[ -d "$HOME/.openclaw/agents" ]]; then
|
|
27
|
-
AGENTS_DIR="$HOME/.openclaw/agents"
|
|
28
|
-
elif [[ -n "${XDG_DATA_HOME:-}" ]] && [[ -d "$XDG_DATA_HOME/openclaw/agents" ]]; then
|
|
29
|
-
AGENTS_DIR="$XDG_DATA_HOME/openclaw/agents"
|
|
30
|
-
elif [[ "$IS_WINDOWS" == "true" ]] && [[ -d "$APPDATA/openclaw/agents" ]]; then
|
|
31
|
-
AGENTS_DIR="$APPDATA/openclaw/agents"
|
|
32
|
-
else
|
|
33
|
-
echo "❌ Cannot find OpenClaw data directory."
|
|
34
|
-
echo ""
|
|
35
|
-
echo " Tried:"
|
|
36
|
-
echo " - \$OPENCLAW_HOME/agents"
|
|
37
|
-
echo " - ~/.openclaw/agents"
|
|
38
|
-
echo " - \$XDG_DATA_HOME/openclaw/agents"
|
|
39
|
-
if [[ "$IS_WINDOWS" == "true" ]]; then
|
|
40
|
-
echo " - %APPDATA%/openclaw/agents"
|
|
41
|
-
fi
|
|
42
|
-
echo ""
|
|
43
|
-
echo " Set OPENCLAW_HOME to your OpenClaw data directory."
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
# === Check dependencies ===
|
|
48
|
-
MISSING=()
|
|
49
|
-
for cmd in jq tail date; do
|
|
50
|
-
if ! command -v "$cmd" &>/dev/null; then
|
|
51
|
-
MISSING+=("$cmd")
|
|
52
|
-
fi
|
|
53
|
-
done
|
|
54
|
-
|
|
55
|
-
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
|
56
|
-
echo "❌ Missing required commands: ${MISSING[*]}"
|
|
57
|
-
echo ""
|
|
58
|
-
echo " Install them:"
|
|
59
|
-
echo ""
|
|
60
|
-
if [[ "$IS_WINDOWS" == "true" ]]; then
|
|
61
|
-
echo " 🪟 Windows (Git Bash / MSYS2):"
|
|
62
|
-
echo " pacman -S jq"
|
|
63
|
-
echo ""
|
|
64
|
-
echo " Or use WSL:"
|
|
65
|
-
echo " sudo apt install jq"
|
|
66
|
-
elif [[ "$OS" == "Darwin" ]]; then
|
|
67
|
-
echo " 🍎 macOS:"
|
|
68
|
-
echo " brew install jq"
|
|
69
|
-
echo ""
|
|
70
|
-
echo " No Homebrew? Install it first:"
|
|
71
|
-
echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
72
|
-
else
|
|
73
|
-
echo " 🐧 Linux:"
|
|
74
|
-
echo " sudo apt install jq # Debian/Ubuntu"
|
|
75
|
-
echo " sudo dnf install jq # Fedora"
|
|
76
|
-
echo " sudo pacman -S jq # Arch"
|
|
77
|
-
echo " sudo apk add jq # Alpine"
|
|
78
|
-
fi
|
|
79
|
-
echo ""
|
|
80
|
-
echo " jq is the only external dependency. tail and date are usually pre-installed."
|
|
81
|
-
exit 1
|
|
82
|
-
fi
|
|
83
|
-
|
|
84
|
-
# === Cross-platform helpers ===
|
|
85
|
-
|
|
86
|
-
# Get file modification time (HH:MM:SS)
|
|
87
|
-
get_mod_time() {
|
|
88
|
-
local file="$1"
|
|
89
|
-
if [[ "$OS" == "Darwin" ]]; then
|
|
90
|
-
stat -f '%Sm' -t '%H:%M:%S' "$file" 2>/dev/null || echo "???"
|
|
91
|
-
elif [[ "$IS_WINDOWS" == "true" ]]; then
|
|
92
|
-
stat -c '%y' "$file" 2>/dev/null | cut -c12-19 || echo "???"
|
|
93
|
-
else
|
|
94
|
-
stat -c '%y' "$file" 2>/dev/null | cut -c12-19 || echo "???"
|
|
95
|
-
fi
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
# Format ISO timestamp → HH:MM:SS
|
|
99
|
-
format_timestamp() {
|
|
100
|
-
local ts="$1"
|
|
101
|
-
if [[ -z "$ts" || "$ts" == "null" || "$ts" == "???" ]]; then
|
|
102
|
-
echo "???"
|
|
103
|
-
return
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
if [[ "$OS" == "Darwin" ]]; then
|
|
107
|
-
if date -j -f "%Y-%m-%dT%H:%M:%S" "$(echo "$ts" | cut -c1-19)" "+%H:%M:%S" 2>/dev/null; then
|
|
108
|
-
return
|
|
109
|
-
fi
|
|
110
|
-
echo "$ts" | cut -c12-19
|
|
111
|
-
else
|
|
112
|
-
date -d "$ts" "+%H:%M:%S" 2>/dev/null || echo "$ts" | cut -c12-19
|
|
113
|
-
fi
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
# Portable grep (no -P on macOS)
|
|
117
|
-
grep_p() {
|
|
118
|
-
if [[ "$OS" == "Darwin" ]]; then
|
|
119
|
-
grep -E "$@"
|
|
120
|
-
else
|
|
121
|
-
grep -P "$@"
|
|
122
|
-
fi
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
# === Argument parsing ===
|
|
126
|
-
COMPACT=false
|
|
127
|
-
SHOW_HISTORY=false
|
|
128
|
-
HISTORY_N=10
|
|
129
|
-
TIME_RANGE=30 # minutes, 0 = all
|
|
130
|
-
|
|
131
|
-
while [[ $# -gt 0 ]]; do
|
|
132
|
-
case "$1" in
|
|
133
|
-
--compact)
|
|
134
|
-
COMPACT=true
|
|
135
|
-
shift
|
|
136
|
-
;;
|
|
137
|
-
--history)
|
|
138
|
-
SHOW_HISTORY=true
|
|
139
|
-
if [[ $# -gt 1 ]] && [[ "$2" =~ ^[0-9]+$ ]]; then
|
|
140
|
-
HISTORY_N="$2"
|
|
141
|
-
shift 2
|
|
142
|
-
else
|
|
143
|
-
shift
|
|
144
|
-
fi
|
|
145
|
-
;;
|
|
146
|
-
--all)
|
|
147
|
-
TIME_RANGE=0
|
|
148
|
-
shift
|
|
149
|
-
;;
|
|
150
|
-
--help|-h)
|
|
151
|
-
echo "clawmonitor — Real-time OpenClaw tool call monitor"
|
|
152
|
-
echo ""
|
|
153
|
-
echo "Usage: clawmonitor [options]"
|
|
154
|
-
echo ""
|
|
155
|
-
echo " --all Monitor all sessions (no time filter)"
|
|
156
|
-
echo " --compact Show only tool name + brief args"
|
|
157
|
-
echo " --history Show recent history before live tail"
|
|
158
|
-
echo " --history N Show last N tool calls from history (default: 10)"
|
|
159
|
-
echo " --help Show this help"
|
|
160
|
-
echo ""
|
|
161
|
-
echo " Monitors all agents under ~/.openclaw/agents/"
|
|
162
|
-
echo " Supports Linux, macOS, and Windows (Git Bash / WSL)"
|
|
163
|
-
echo ""
|
|
164
|
-
echo " Environment variables:"
|
|
165
|
-
echo " OPENCLAW_HOME Custom OpenClaw data directory"
|
|
166
|
-
echo " NO_COLOR Disable colored output"
|
|
167
|
-
exit 0
|
|
168
|
-
;;
|
|
169
|
-
[0-9]*)
|
|
170
|
-
if $SHOW_HISTORY; then
|
|
171
|
-
HISTORY_N="$1"
|
|
172
|
-
shift
|
|
173
|
-
else
|
|
174
|
-
echo "Unknown argument: $1"
|
|
175
|
-
exit 1
|
|
176
|
-
fi
|
|
177
|
-
;;
|
|
178
|
-
*)
|
|
179
|
-
echo "Unknown argument: $1"
|
|
180
|
-
exit 1
|
|
181
|
-
;;
|
|
182
|
-
esac
|
|
183
|
-
done
|
|
184
|
-
|
|
185
|
-
# === Color setup ===
|
|
186
|
-
if [[ -t 1 ]] && [[ "${NO_COLOR:-}" == "" ]]; then
|
|
187
|
-
RST='\033[0m' BLD='\033[1m' DIM='\033[2m'
|
|
188
|
-
CYN='\033[36m' GRN='\033[32m' YLW='\033[33m' MAG='\033[35m' RED='\033[31m'
|
|
189
|
-
BLU='\033[34m' WHT='\033[37m'
|
|
190
|
-
else
|
|
191
|
-
RST='' BLD='' DIM=''
|
|
192
|
-
CYN='' GRN='' YLW='' MAG='' RED=''
|
|
193
|
-
BLU='' WHT=''
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
|
-
# === Session management ===
|
|
197
|
-
|
|
198
|
-
find_sessions() {
|
|
199
|
-
local find_cmd=(find "$AGENTS_DIR" -path "*/sessions/*.jsonl" -type f)
|
|
200
|
-
if [[ "$TIME_RANGE" -eq 0 ]]; then
|
|
201
|
-
"${find_cmd[@]}"
|
|
202
|
-
else
|
|
203
|
-
local now_epoch
|
|
204
|
-
now_epoch=$(date +%s)
|
|
205
|
-
|
|
206
|
-
"${find_cmd[@]}" | while IFS= read -r file; do
|
|
207
|
-
local mod_epoch
|
|
208
|
-
if [[ "$OS" == "Darwin" ]]; then
|
|
209
|
-
mod_epoch=$(stat -f '%m' "$file" 2>/dev/null || echo 0)
|
|
210
|
-
else
|
|
211
|
-
mod_epoch=$(stat -c '%Y' "$file" 2>/dev/null || echo 0)
|
|
212
|
-
fi
|
|
213
|
-
|
|
214
|
-
if [[ "$mod_epoch" -gt 0 ]] && (( now_epoch - mod_epoch <= TIME_RANGE * 60 )); then
|
|
215
|
-
echo "$file"
|
|
216
|
-
fi
|
|
217
|
-
done
|
|
218
|
-
fi
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
# Extract readable session name from conversation_label
|
|
222
|
-
get_session_label() {
|
|
223
|
-
local file="$1"
|
|
224
|
-
local agent_name
|
|
225
|
-
agent_name=$(echo "$file" | sed "s|$AGENTS_DIR/||;s|/sessions/.*||")
|
|
226
|
-
|
|
227
|
-
local filename
|
|
228
|
-
filename=$(basename "$file" .jsonl)
|
|
229
|
-
|
|
230
|
-
local conv_label
|
|
231
|
-
conv_label=$(jq -r 'select(.type=="message" and .message.role=="user") |
|
|
232
|
-
.message.content[] | select(.type=="text") | .text' "$file" 2>/dev/null | \
|
|
233
|
-
head -20 | \
|
|
234
|
-
grep_p -o '"conversation_label"[[:space:]]*:[[:space:]]*"[^"]*"' 2>/dev/null | head -1 | \
|
|
235
|
-
sed 's/"conversation_label" : "//;s/"conversation_label": "//;s/"$//')
|
|
236
|
-
|
|
237
|
-
if [[ -n "$conv_label" ]]; then
|
|
238
|
-
local group topic group_name
|
|
239
|
-
group=$(echo "$conv_label" | grep_p -o 'id:[^ ]+' 2>/dev/null | sed 's/id://')
|
|
240
|
-
topic=$(echo "$conv_label" | grep_p -o 'topic:[0-9]+' 2>/dev/null | sed 's/topic:/t/')
|
|
241
|
-
group_name=$(echo "$conv_label" | grep_p -o '^[^ ]+' 2>/dev/null)
|
|
242
|
-
|
|
243
|
-
if [[ -n "$topic" ]]; then
|
|
244
|
-
echo "${agent_name}/${group_name}/${topic}"
|
|
245
|
-
elif [[ -n "$group_name" ]]; then
|
|
246
|
-
echo "${agent_name}/${group_name}"
|
|
247
|
-
else
|
|
248
|
-
echo "${agent_name}/${conv_label}"
|
|
249
|
-
fi
|
|
250
|
-
else
|
|
251
|
-
local short_id topic_suffix
|
|
252
|
-
short_id=$(echo "$filename" | sed 's/-topic-[0-9]*$//;s/-\([0-9a-f]\{4\}\).*/..*\1/')
|
|
253
|
-
topic_suffix=$(echo "$filename" | grep_p -o 'topic-[0-9]+' 2>/dev/null || true)
|
|
254
|
-
if [[ -n "$topic_suffix" ]]; then
|
|
255
|
-
echo "${agent_name}/DM/${topic_suffix}"
|
|
256
|
-
else
|
|
257
|
-
echo "${agent_name}/DM/${short_id}"
|
|
258
|
-
fi
|
|
259
|
-
fi
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
# Session label store (portable: works on bash 3.2+ / macOS)
|
|
263
|
-
# Uses a temp file as key\0value pairs instead of associative arrays
|
|
264
|
-
LABEL_STORE=$(mktemp /tmp/clawmonitor-labels.XXXXXX)
|
|
265
|
-
trap 'rm -f "$LABEL_STORE"' EXIT
|
|
266
|
-
|
|
267
|
-
_label_set() {
|
|
268
|
-
local key="$1" val="$2"
|
|
269
|
-
grep -v "^${key}"$'\t' "$LABEL_STORE" > "${LABEL_STORE}.tmp" 2>/dev/null || true
|
|
270
|
-
printf '%s\t%s\n' "$key" "$val" >> "${LABEL_STORE}.tmp"
|
|
271
|
-
mv "${LABEL_STORE}.tmp" "$LABEL_STORE"
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
_label_get() {
|
|
275
|
-
local key="$1"
|
|
276
|
-
local result
|
|
277
|
-
result=$(grep "^${key}"$'\t' "$LABEL_STORE" 2>/dev/null | head -1 | cut -f2-)
|
|
278
|
-
echo "${result:-$2}"
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
cache_labels() {
|
|
282
|
-
local files="$1"
|
|
283
|
-
for f in $files; do
|
|
284
|
-
local key
|
|
285
|
-
key=$(basename "$f")
|
|
286
|
-
_label_set "$key" "$(get_session_label "$f")"
|
|
287
|
-
done
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
# Extract tool calls from a single session JSONL
|
|
291
|
-
extract_tool_calls() {
|
|
292
|
-
local file="$1"
|
|
293
|
-
local limit="${2:-0}"
|
|
294
|
-
local filename
|
|
295
|
-
filename=$(basename "$file")
|
|
296
|
-
|
|
297
|
-
local filter='select(.type=="message" and .message.role=="assistant") |
|
|
298
|
-
{ts: (.timestamp // .message.timestamp), file: "'"${filename}"'", content: [.message.content[] | select(.type=="toolCall")]} |
|
|
299
|
-
select(.content | length > 0)'
|
|
300
|
-
|
|
301
|
-
if [[ "$limit" -gt 0 ]]; then
|
|
302
|
-
jq -c "$filter" "$file" 2>/dev/null | tail -"$limit"
|
|
303
|
-
else
|
|
304
|
-
jq -c "$filter" "$file" 2>/dev/null
|
|
305
|
-
fi
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
# Format a single tool call entry
|
|
309
|
-
format_tc() {
|
|
310
|
-
local json="$1"
|
|
311
|
-
local ts filename label
|
|
312
|
-
ts=$(echo "$json" | jq -r '.ts // "???"')
|
|
313
|
-
filename=$(echo "$json" | jq -r '.file // "?"')
|
|
314
|
-
label=$(_label_get "$filename" "$filename")
|
|
315
|
-
|
|
316
|
-
local time_str
|
|
317
|
-
time_str=$(format_timestamp "$ts")
|
|
318
|
-
|
|
319
|
-
echo "$json" | jq -c '.content[]' 2>/dev/null | while IFS= read -r tc; do
|
|
320
|
-
local tool_name tool_id
|
|
321
|
-
tool_name=$(echo "$tc" | jq -r '.name // "?"')
|
|
322
|
-
tool_id=$(echo "$tc" | jq -r '.id // "?"' | cut -c1-12)
|
|
323
|
-
|
|
324
|
-
if $COMPACT; then
|
|
325
|
-
local brief_args
|
|
326
|
-
brief_args=$(echo "$tc" | jq -r '
|
|
327
|
-
.arguments | to_entries[:2] |
|
|
328
|
-
map("\(.key)=\(.value | tostring | .[0:80])") | join(" ")
|
|
329
|
-
' 2>/dev/null)
|
|
330
|
-
printf "${GRN}%-13s${RST} ${BLU}%-28s${RST} ${CYN}%-9s${RST} %s\n" \
|
|
331
|
-
"$tool_name" "${label:0:28}" "$time_str" "$brief_args"
|
|
332
|
-
else
|
|
333
|
-
printf "\n${BLD}${YLW}⏱ %s${RST} ${BLU}%s${RST} ${MAG}%s${RST}\n" \
|
|
334
|
-
"$time_str" "${label}" "$tool_id"
|
|
335
|
-
printf " ${GRN}▶ %s${RST}\n" "$tool_name"
|
|
336
|
-
|
|
337
|
-
echo "$tc" | jq -c '.arguments | to_entries[]' 2>/dev/null | while IFS= read -r entry; do
|
|
338
|
-
local key val
|
|
339
|
-
key=$(echo "$entry" | jq -r '.key')
|
|
340
|
-
val=$(echo "$entry" | jq -r '.value | tostring | .[0:300]')
|
|
341
|
-
[[ ${#val} -ge 300 ]] && val="${val}…"
|
|
342
|
-
printf " ${CYN}%-14s${RST} %s\n" "$key" "$val"
|
|
343
|
-
done
|
|
344
|
-
fi
|
|
345
|
-
done
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
# === Main ===
|
|
349
|
-
|
|
350
|
-
sessions=$(find_sessions | sort)
|
|
351
|
-
session_count=$(echo "$sessions" | grep -c . 2>/dev/null || echo 0)
|
|
352
|
-
|
|
353
|
-
if [[ "$session_count" -eq 0 ]]; then
|
|
354
|
-
echo -e "${RED}No sessions found under ${AGENTS_DIR}${RST}"
|
|
355
|
-
echo "Try --all or wait for activity."
|
|
356
|
-
exit 1
|
|
357
|
-
fi
|
|
358
|
-
|
|
359
|
-
cache_labels "$sessions"
|
|
360
|
-
|
|
361
|
-
echo -e "${BLD}🔧 OpenClaw Tool Call Monitor${RST}"
|
|
362
|
-
echo -e "${DIM}Watching ${session_count} session(s) on ${OS} — Ctrl+C to stop${RST}"
|
|
363
|
-
echo ""
|
|
364
|
-
|
|
365
|
-
# List all sessions
|
|
366
|
-
echo -e "${BLD}📋 Active sessions:${RST}"
|
|
367
|
-
for f in $sessions; do
|
|
368
|
-
filename=$(basename "$f")
|
|
369
|
-
label=$(_label_get "$filename" "$filename")
|
|
370
|
-
mod_time=$(get_mod_time "$f")
|
|
371
|
-
printf " ${DIM}%-9s${RST} ${BLU}%-35s${RST} ${DIM}(last: %s)${RST}\n" \
|
|
372
|
-
"$(echo "$filename" | cut -c1-8)" "${label:0:35}" "$mod_time"
|
|
373
|
-
done
|
|
374
|
-
|
|
375
|
-
if $COMPACT; then
|
|
376
|
-
printf "\n${DIM}%-13s %-28s %-9s %s${RST}\n" "TOOL" "SESSION" "TIME" "ARGS"
|
|
377
|
-
echo "-------------------------------------------------------------------------"
|
|
378
|
-
fi
|
|
379
|
-
|
|
380
|
-
# Default: show last 10 history entries
|
|
381
|
-
if ! $SHOW_HISTORY; then
|
|
382
|
-
SHOW_HISTORY=true
|
|
383
|
-
fi
|
|
384
|
-
|
|
385
|
-
# Show history sorted by time
|
|
386
|
-
if $SHOW_HISTORY; then
|
|
387
|
-
echo -e "\n${BLD}📜 Recent tool calls (sorted by time):${RST}"
|
|
388
|
-
for f in $sessions; do
|
|
389
|
-
extract_tool_calls "$f" 0
|
|
390
|
-
done | jq -s 'sort_by(.ts)' | jq -c '.[]' > /tmp/openclaw-tc-history.jsonl
|
|
391
|
-
|
|
392
|
-
if [[ "$HISTORY_N" -gt 0 ]]; then
|
|
393
|
-
tail -"$HISTORY_N" /tmp/openclaw-tc-history.jsonl | while IFS= read -r line; do
|
|
394
|
-
format_tc "$line"
|
|
395
|
-
done
|
|
396
|
-
else
|
|
397
|
-
cat /tmp/openclaw-tc-history.jsonl | while IFS= read -r line; do
|
|
398
|
-
format_tc "$line"
|
|
399
|
-
done
|
|
400
|
-
fi
|
|
401
|
-
rm -f /tmp/openclaw-tc-history.jsonl
|
|
402
|
-
|
|
403
|
-
echo -e "\n${BLD}🔴 Live monitoring:${RST}"
|
|
404
|
-
if $COMPACT; then
|
|
405
|
-
echo "-------------------------------------------------------------------------"
|
|
406
|
-
fi
|
|
407
|
-
fi
|
|
408
|
-
|
|
409
|
-
# Live monitoring with glob pattern for auto-tracking new sessions
|
|
410
|
-
SESSIONS_GLOB="${AGENTS_DIR}/*/sessions/*.jsonl"
|
|
411
|
-
shopt -s nullglob
|
|
412
|
-
live_session_files=("$AGENTS_DIR"/*/sessions/*.jsonl)
|
|
413
|
-
shopt -u nullglob
|
|
414
|
-
|
|
415
|
-
tail -F -n 0 $SESSIONS_GLOB 2>/dev/null | {
|
|
416
|
-
current_file=""
|
|
417
|
-
if [[ "${#live_session_files[@]}" -eq 1 ]]; then
|
|
418
|
-
current_file="${live_session_files[0]}"
|
|
419
|
-
fi
|
|
420
|
-
while IFS= read -r line; do
|
|
421
|
-
# Detect tail -F file switch header
|
|
422
|
-
if [[ "$line" == "==>"* ]]; then
|
|
423
|
-
current_file=$(echo "$line" | sed 's/==> \(.*\) <==/\1/')
|
|
424
|
-
continue
|
|
425
|
-
fi
|
|
426
|
-
|
|
427
|
-
# Quick filter
|
|
428
|
-
echo "$line" | grep -q '"toolCall"' || continue
|
|
429
|
-
echo "$line" | grep -q '"assistant"' || continue
|
|
430
|
-
|
|
431
|
-
filename=$(basename "${current_file}")
|
|
432
|
-
# Dynamic label lookup for new sessions
|
|
433
|
-
if [[ -z "$(_label_get "$filename" "")" ]]; then
|
|
434
|
-
_label_set "$filename" "$(get_session_label "${current_file}")"
|
|
435
|
-
fi
|
|
436
|
-
label=$(_label_get "$filename" "$filename")
|
|
437
|
-
|
|
438
|
-
ts=$(echo "$line" | jq -r '.timestamp // .message.timestamp // "???"' 2>/dev/null)
|
|
439
|
-
time_str=$(format_timestamp "$ts")
|
|
440
|
-
|
|
441
|
-
echo "$line" | jq -c '.message.content[] | select(.type=="toolCall")' 2>/dev/null | while IFS= read -r tc; do
|
|
442
|
-
tool_name=$(echo "$tc" | jq -r '.name // "?"')
|
|
443
|
-
tool_id=$(echo "$tc" | jq -r '.id // "?"' | cut -c1-12)
|
|
444
|
-
|
|
445
|
-
if $COMPACT; then
|
|
446
|
-
brief_args=$(echo "$tc" | jq -r '
|
|
447
|
-
.arguments | to_entries[:2] |
|
|
448
|
-
map("\(.key)=\(.value | tostring | .[0:80])") | join(" ")
|
|
449
|
-
' 2>/dev/null)
|
|
450
|
-
printf "${GRN}%-13s${RST} ${BLU}%-28s${RST} ${CYN}%-9s${RST} %s\n" \
|
|
451
|
-
"$tool_name" "${label:0:28}" "$time_str" "$brief_args"
|
|
452
|
-
else
|
|
453
|
-
printf "\n${BLD}${YLW}⏱ %s${RST} ${BLU}%s${RST} ${MAG}%s${RST}\n" \
|
|
454
|
-
"$time_str" "${label}" "$tool_id"
|
|
455
|
-
printf " ${GRN}▶ %s${RST}\n" "$tool_name"
|
|
456
|
-
|
|
457
|
-
echo "$tc" | jq -c '.arguments | to_entries[]' 2>/dev/null | while IFS= read -r entry; do
|
|
458
|
-
key=$(echo "$entry" | jq -r '.key')
|
|
459
|
-
val=$(echo "$entry" | jq -r '.value | tostring | .[0:300]')
|
|
460
|
-
[[ ${#val} -ge 300 ]] && val="${val}…"
|
|
461
|
-
printf " ${CYN}%-14s${RST} %s\n" "$key" "$val"
|
|
462
|
-
done
|
|
463
|
-
fi
|
|
464
|
-
done
|
|
465
|
-
done
|
|
466
|
-
}
|