@onlooker-community/ecosystem 0.4.0 → 0.6.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/.claude/settings.json +5 -0
- package/.claude/settings.local.json +5 -0
- package/.github/workflows/publish-npm.yml +1 -21
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/hooks/hooks.json +14 -0
- package/package.json +1 -1
- package/scripts/hooks/session-duration-tracker.sh +39 -0
- package/scripts/hooks/turn-tracker.sh +38 -0
- package/scripts/lib/session-tracker.sh +86 -0
- package/scripts/lib/turn-tracker.sh +68 -0
- package/test/bats/config.bats +18 -0
- package/test/bats/user-prompt-submit-tracker.bats +74 -0
- package/test/fixtures/hook-inputs/user-prompt-submit-turn2.json +8 -0
- package/test/fixtures/hook-inputs/user-prompt-submit.json +8 -0
|
@@ -77,30 +77,10 @@ jobs:
|
|
|
77
77
|
echo "ERROR: package.json version ($PKG_VERSION) does not match tag ($TAG_VERSION)"
|
|
78
78
|
exit 1
|
|
79
79
|
fi
|
|
80
|
-
|
|
81
|
-
test:
|
|
82
|
-
name: Test
|
|
83
|
-
runs-on: ubuntu-latest
|
|
84
|
-
strategy:
|
|
85
|
-
matrix:
|
|
86
|
-
node: ['20', '22']
|
|
87
|
-
steps:
|
|
88
|
-
- uses: actions/checkout@v4
|
|
89
|
-
|
|
90
|
-
- uses: actions/setup-node@v4
|
|
91
|
-
with:
|
|
92
|
-
node-version: ${{ matrix.node }}
|
|
93
|
-
cache: npm
|
|
94
|
-
|
|
95
|
-
- run: npm ci
|
|
96
|
-
- run: npm run build
|
|
97
|
-
- run: npm test
|
|
98
|
-
- run: npm run typecheck
|
|
99
|
-
|
|
100
80
|
publish:
|
|
101
81
|
name: Publish to npm
|
|
102
82
|
runs-on: ubuntu-latest
|
|
103
|
-
needs: [validate
|
|
83
|
+
needs: [validate]
|
|
104
84
|
environment: npm-publish
|
|
105
85
|
steps:
|
|
106
86
|
- uses: actions/checkout@v4
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0](https://github.com/onlooker-community/ecosystem/compare/v0.5.0...v0.6.0) (2026-05-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add settings.json for plugin configuration ([67fbdfe](https://github.com/onlooker-community/ecosystem/commit/67fbdfe37f067a45801e7d0355c4a533b687f6b2))
|
|
9
|
+
|
|
10
|
+
## [0.5.0](https://github.com/onlooker-community/ecosystem/compare/v0.4.0...v0.5.0) (2026-05-22)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **hooks:** add UserPromptSubmit turn and session duration trackers ([#12](https://github.com/onlooker-community/ecosystem/issues/12)) ([cbb7657](https://github.com/onlooker-community/ecosystem/commit/cbb7657979ed144efce506e6b487e037679b9462))
|
|
16
|
+
|
|
3
17
|
## [0.4.0](https://github.com/onlooker-community/ecosystem/compare/v0.3.3...v0.4.0) (2026-05-22)
|
|
4
18
|
|
|
5
19
|
|
package/hooks/hooks.json
CHANGED
|
@@ -40,6 +40,20 @@
|
|
|
40
40
|
]
|
|
41
41
|
}
|
|
42
42
|
],
|
|
43
|
+
"UserPromptSubmit": [
|
|
44
|
+
{
|
|
45
|
+
"hooks": [
|
|
46
|
+
{
|
|
47
|
+
"type": "command",
|
|
48
|
+
"command": "\"$CLAUDE_PLUGIN_ROOT\"/scripts/hooks/turn-tracker.sh"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "command",
|
|
52
|
+
"command": "\"$CLAUDE_PLUGIN_ROOT\"/scripts/hooks/session-duration-tracker.sh"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
43
57
|
"PostToolUse": [
|
|
44
58
|
{
|
|
45
59
|
"matcher": "*",
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Onlooker Session Duration Tracker
|
|
3
|
+
# Invoked by UserPromptSubmit when the user submits a prompt.
|
|
4
|
+
#
|
|
5
|
+
# Updates session_duration_ms on the tracker and injects turn + elapsed time
|
|
6
|
+
# into Claude's context via UserPromptSubmit additionalContext.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# echo "$INPUT" | session-duration-tracker.sh
|
|
10
|
+
|
|
11
|
+
set -uo pipefail # No -e: never block prompt submission
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
source "$SCRIPT_DIR/../lib/validate-path.sh"
|
|
15
|
+
source "$SCRIPT_DIR/../lib/session-tracker.sh"
|
|
16
|
+
|
|
17
|
+
hook_register "session-duration-tracker" "Session Duration Tracker" "Surfaces session elapsed time on each user prompt"
|
|
18
|
+
|
|
19
|
+
INPUT=$(cat)
|
|
20
|
+
hook_set_context "$INPUT" "UserPromptSubmit"
|
|
21
|
+
|
|
22
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
23
|
+
|
|
24
|
+
session_tracker_update_duration "$SESSION_ID" || hook_failure "Failed to update session duration"
|
|
25
|
+
|
|
26
|
+
CONTEXT=$(session_tracker_build_duration_context "$SESSION_ID")
|
|
27
|
+
if [[ -n "$CONTEXT" ]]; then
|
|
28
|
+
jq -n \
|
|
29
|
+
--arg ctx "$CONTEXT" \
|
|
30
|
+
'{
|
|
31
|
+
hookSpecificOutput: {
|
|
32
|
+
hookEventName: "UserPromptSubmit",
|
|
33
|
+
additionalContext: $ctx
|
|
34
|
+
}
|
|
35
|
+
}'
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
hook_success
|
|
39
|
+
exit 0
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Onlooker Turn Tracker
|
|
3
|
+
# Invoked by UserPromptSubmit when the user submits a prompt.
|
|
4
|
+
#
|
|
5
|
+
# Advances per-session turn_number (first prompt stays at turn 1) and emits
|
|
6
|
+
# canonical session.prompt for telemetry.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# echo "$INPUT" | turn-tracker.sh
|
|
10
|
+
|
|
11
|
+
set -uo pipefail # No -e: never block prompt submission
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
source "$SCRIPT_DIR/../lib/validate-path.sh"
|
|
15
|
+
source "$SCRIPT_DIR/../lib/onlooker-schema.sh"
|
|
16
|
+
source "$SCRIPT_DIR/../lib/tool-history.sh"
|
|
17
|
+
source "$SCRIPT_DIR/../lib/session-tracker.sh"
|
|
18
|
+
source "$SCRIPT_DIR/../lib/turn-tracker.sh"
|
|
19
|
+
|
|
20
|
+
hook_register "turn-tracker" "Turn Tracker" "Tracks conversation turns and emits session.prompt"
|
|
21
|
+
|
|
22
|
+
INPUT=$(cat)
|
|
23
|
+
hook_set_context "$INPUT" "UserPromptSubmit"
|
|
24
|
+
|
|
25
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
26
|
+
PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""')
|
|
27
|
+
|
|
28
|
+
turn_tracker_on_user_prompt "$SESSION_ID" || hook_failure "Failed to advance turn state"
|
|
29
|
+
turn_state_export "$SESSION_ID"
|
|
30
|
+
|
|
31
|
+
PAYLOAD=$(turn_tracker_build_prompt_payload "$SESSION_ID" "$PROMPT")
|
|
32
|
+
if [[ -n "$PAYLOAD" ]]; then
|
|
33
|
+
session_tracker_emit "$SESSION_ID" "session.prompt" "$PAYLOAD" \
|
|
34
|
+
|| hook_failure "Failed to emit session.prompt"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
hook_success
|
|
38
|
+
exit 0
|
|
@@ -142,6 +142,92 @@ session_tracker_build_end_payload() {
|
|
|
142
142
|
}'
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
# Elapsed session time in milliseconds (0 when start_time_ms is unset).
|
|
146
|
+
# Usage: duration_ms=$(session_tracker_duration_ms "$SESSION_ID")
|
|
147
|
+
session_tracker_duration_ms() {
|
|
148
|
+
local session_id="${1:-}"
|
|
149
|
+
[[ -z "$session_id" || "$session_id" == "null" ]] && echo 0 && return 0
|
|
150
|
+
|
|
151
|
+
local tracker_file="$ONLOOKER_SESSION_TRACKERS_DIR/$session_id"
|
|
152
|
+
local now_ms start_ms duration_ms
|
|
153
|
+
now_ms=$(session_tracker_now_ms)
|
|
154
|
+
|
|
155
|
+
if [[ ! -f "$tracker_file" ]]; then
|
|
156
|
+
echo 0
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
start_ms=$(jq -r '.start_time_ms // 0' "$tracker_file" 2>/dev/null) || start_ms=0
|
|
161
|
+
if [[ ! "$start_ms" =~ ^[0-9]+$ ]] || (( start_ms <= 0 )); then
|
|
162
|
+
echo 0
|
|
163
|
+
return 0
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
duration_ms=$((now_ms - start_ms))
|
|
167
|
+
(( duration_ms < 0 )) && duration_ms=0
|
|
168
|
+
echo "$duration_ms"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Human-readable duration for hook context (e.g. "12m 34s", "45s").
|
|
172
|
+
# Usage: label=$(session_tracker_format_duration 754000)
|
|
173
|
+
session_tracker_format_duration() {
|
|
174
|
+
local duration_ms="${1:-0}"
|
|
175
|
+
[[ ! "$duration_ms" =~ ^[0-9]+$ ]] && duration_ms=0
|
|
176
|
+
|
|
177
|
+
local total_sec=$((duration_ms / 1000))
|
|
178
|
+
local hours=$((total_sec / 3600))
|
|
179
|
+
local minutes=$(((total_sec % 3600) / 60))
|
|
180
|
+
local seconds=$((total_sec % 60))
|
|
181
|
+
|
|
182
|
+
if (( hours > 0 )); then
|
|
183
|
+
printf '%dh %dm' "$hours" "$minutes"
|
|
184
|
+
elif (( minutes > 0 )); then
|
|
185
|
+
printf '%dm %ds' "$minutes" "$seconds"
|
|
186
|
+
else
|
|
187
|
+
printf '%ds' "$seconds"
|
|
188
|
+
fi
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# Persist session_duration_ms on the per-session tracker file.
|
|
192
|
+
# Usage: session_tracker_update_duration "$SESSION_ID"
|
|
193
|
+
session_tracker_update_duration() {
|
|
194
|
+
local session_id="${1:-}"
|
|
195
|
+
[[ -z "$session_id" || "$session_id" == "null" ]] && return 0
|
|
196
|
+
|
|
197
|
+
turn_state_ensure_session "$session_id" || return 1
|
|
198
|
+
|
|
199
|
+
local tracker_file="$ONLOOKER_SESSION_TRACKERS_DIR/$session_id"
|
|
200
|
+
local duration_ms
|
|
201
|
+
duration_ms=$(session_tracker_duration_ms "$session_id")
|
|
202
|
+
|
|
203
|
+
local temp_file
|
|
204
|
+
temp_file=$(mktemp)
|
|
205
|
+
if ! jq --argjson duration_ms "$duration_ms" \
|
|
206
|
+
'.session_duration_ms = $duration_ms' \
|
|
207
|
+
"$tracker_file" >"$temp_file" 2>/dev/null; then
|
|
208
|
+
rm -f "$temp_file"
|
|
209
|
+
return 1
|
|
210
|
+
fi
|
|
211
|
+
mv "$temp_file" "$tracker_file"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
# Build additionalContext line for UserPromptSubmit (turn + elapsed time).
|
|
215
|
+
# Usage: context=$(session_tracker_build_duration_context "$SESSION_ID")
|
|
216
|
+
session_tracker_build_duration_context() {
|
|
217
|
+
local session_id="${1:-}"
|
|
218
|
+
local duration_ms turn_number elapsed
|
|
219
|
+
duration_ms=$(session_tracker_duration_ms "$session_id")
|
|
220
|
+
elapsed=$(session_tracker_format_duration "$duration_ms")
|
|
221
|
+
|
|
222
|
+
if [[ -f "$ONLOOKER_SESSION_TRACKERS_DIR/$session_id" ]]; then
|
|
223
|
+
turn_number=$(jq -r '.turn_number // 1' "$ONLOOKER_SESSION_TRACKERS_DIR/$session_id" 2>/dev/null) || turn_number=1
|
|
224
|
+
else
|
|
225
|
+
turn_number=1
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
printf 'Onlooker session: turn %s · elapsed %s' "$turn_number" "$elapsed"
|
|
229
|
+
}
|
|
230
|
+
|
|
145
231
|
# Emit a validated canonical session event and append to logs.
|
|
146
232
|
# Usage: session_tracker_emit "$SESSION_ID" "session.start" "$payload_json"
|
|
147
233
|
session_tracker_emit() {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Turn tracking helpers for UserPromptSubmit hooks.
|
|
3
|
+
#
|
|
4
|
+
# Source after validate-path.sh, onlooker-schema.sh, tool-history.sh, session-tracker.sh:
|
|
5
|
+
# source "$CLAUDE_PLUGIN_ROOT/scripts/lib/turn-tracker.sh"
|
|
6
|
+
|
|
7
|
+
# Truncate prompt text for session.prompt input_summary.
|
|
8
|
+
# Usage: summary=$(turn_tracker_summarize_prompt "$PROMPT")
|
|
9
|
+
turn_tracker_summarize_prompt() {
|
|
10
|
+
local prompt="${1:-}"
|
|
11
|
+
[[ -z "$prompt" ]] && return 0
|
|
12
|
+
|
|
13
|
+
local summary
|
|
14
|
+
summary=$(printf '%s' "$prompt" | tr '\n' ' ' | sed 's/ */ /g' | sed 's/^ //;s/ $//')
|
|
15
|
+
if ((${#summary} > 200)); then
|
|
16
|
+
summary="${summary:0:200}…"
|
|
17
|
+
fi
|
|
18
|
+
printf '%s' "$summary"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Advance turn state when the user submits a prompt (first prompt stays at turn 1).
|
|
22
|
+
# Usage: turn_tracker_on_user_prompt "$SESSION_ID"
|
|
23
|
+
turn_tracker_on_user_prompt() {
|
|
24
|
+
local session_id="${1:-}"
|
|
25
|
+
[[ -z "$session_id" || "$session_id" == "null" ]] && return 0
|
|
26
|
+
|
|
27
|
+
turn_state_ensure_session "$session_id" || return 1
|
|
28
|
+
|
|
29
|
+
local tracker_file="$ONLOOKER_SESSION_TRACKERS_DIR/$session_id"
|
|
30
|
+
local seen
|
|
31
|
+
seen=$(jq -r '.user_prompts_seen // false' "$tracker_file" 2>/dev/null) || seen="false"
|
|
32
|
+
|
|
33
|
+
if [[ "$seen" == "true" ]]; then
|
|
34
|
+
turn_state_next_turn "$session_id" || return 1
|
|
35
|
+
else
|
|
36
|
+
local temp_file
|
|
37
|
+
temp_file=$(mktemp)
|
|
38
|
+
if ! jq '.user_prompts_seen = true | .turn_tool_seq = 0' \
|
|
39
|
+
"$tracker_file" >"$temp_file" 2>/dev/null; then
|
|
40
|
+
rm -f "$temp_file"
|
|
41
|
+
return 1
|
|
42
|
+
fi
|
|
43
|
+
mv "$temp_file" "$tracker_file"
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Build session.prompt payload for the current turn.
|
|
48
|
+
# Usage: payload=$(turn_tracker_build_prompt_payload "$SESSION_ID" "$PROMPT")
|
|
49
|
+
turn_tracker_build_prompt_payload() {
|
|
50
|
+
local session_id="${1:-}"
|
|
51
|
+
local prompt="${2:-}"
|
|
52
|
+
[[ -z "$session_id" || "$session_id" == "null" ]] && return 1
|
|
53
|
+
|
|
54
|
+
local turn_number summary
|
|
55
|
+
if [[ -f "$ONLOOKER_SESSION_TRACKERS_DIR/$session_id" ]]; then
|
|
56
|
+
turn_number=$(jq -r '.turn_number // 1' "$ONLOOKER_SESSION_TRACKERS_DIR/$session_id" 2>/dev/null) || turn_number=1
|
|
57
|
+
else
|
|
58
|
+
turn_number=1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
summary=$(turn_tracker_summarize_prompt "$prompt")
|
|
62
|
+
|
|
63
|
+
jq -n \
|
|
64
|
+
--argjson turn_number "$turn_number" \
|
|
65
|
+
--arg summary "$summary" \
|
|
66
|
+
'{turn_number: $turn_number}
|
|
67
|
+
+ (if $summary != "" then {input_summary: $summary} else {} end)'
|
|
68
|
+
}
|
package/test/bats/config.bats
CHANGED
|
@@ -84,6 +84,24 @@ setup_file() {
|
|
|
84
84
|
[[ "$hook_cmd" == *tool-history-tracker.sh ]]
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
@test "hooks.json UserPromptSubmit references turn and session-duration trackers" {
|
|
88
|
+
run jq -e '.hooks.UserPromptSubmit[0].hooks | length == 2' "${REPO_ROOT}/hooks/hooks.json"
|
|
89
|
+
[ "$status" -eq 0 ]
|
|
90
|
+
|
|
91
|
+
local turn_cmd duration_cmd
|
|
92
|
+
turn_cmd=$(jq -r '.hooks.UserPromptSubmit[0].hooks[0].command' "${REPO_ROOT}/hooks/hooks.json")
|
|
93
|
+
duration_cmd=$(jq -r '.hooks.UserPromptSubmit[0].hooks[1].command' "${REPO_ROOT}/hooks/hooks.json")
|
|
94
|
+
[[ "$turn_cmd" == *turn-tracker.sh ]]
|
|
95
|
+
[[ "$duration_cmd" == *session-duration-tracker.sh ]]
|
|
96
|
+
|
|
97
|
+
for hook_cmd in "$turn_cmd" "$duration_cmd"; do
|
|
98
|
+
local script_path="${hook_cmd//\$CLAUDE_PLUGIN_ROOT/$REPO_ROOT}"
|
|
99
|
+
script_path="${script_path//\"/}"
|
|
100
|
+
run test -x "$script_path"
|
|
101
|
+
[ "$status" -eq 0 ]
|
|
102
|
+
done
|
|
103
|
+
}
|
|
104
|
+
|
|
87
105
|
@test "hooks.json SessionStart references session-start-tracker" {
|
|
88
106
|
run jq -e '.hooks.SessionStart[0].matcher == "*"' "${REPO_ROOT}/hooks/hooks.json"
|
|
89
107
|
[ "$status" -eq 0 ]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
setup() {
|
|
4
|
+
# shellcheck source=../helpers/setup.bash
|
|
5
|
+
source "${BATS_TEST_DIRNAME}/../helpers/setup.bash"
|
|
6
|
+
load_validate_path
|
|
7
|
+
export CLAUDE_PLUGIN_ROOT="${REPO_ROOT}"
|
|
8
|
+
source "${REPO_ROOT}/scripts/lib/onlooker-schema.sh"
|
|
9
|
+
source "${REPO_ROOT}/scripts/lib/tool-history.sh"
|
|
10
|
+
source "${REPO_ROOT}/scripts/lib/session-tracker.sh"
|
|
11
|
+
source "${REPO_ROOT}/scripts/lib/turn-tracker.sh"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@test "turn-tracker emits session.prompt on first user prompt at turn 1" {
|
|
15
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/user-prompt-submit.json"
|
|
16
|
+
local session_id="prompt-session-001"
|
|
17
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
18
|
+
local history_file="${ONLOOKER_SESSION_HISTORY_DIR}/${session_id}.jsonl"
|
|
19
|
+
rm -f "$tracker" "$history_file"
|
|
20
|
+
|
|
21
|
+
turn_state_ensure_session "$session_id"
|
|
22
|
+
jq '.start_time_ms = 1000' "$tracker" >"${tracker}.tmp" && mv "${tracker}.tmp" "$tracker"
|
|
23
|
+
|
|
24
|
+
run bash -c "cat '${fixture}' | '${REPO_ROOT}/scripts/hooks/turn-tracker.sh' 2>/dev/null"
|
|
25
|
+
[ "$status" -eq 0 ]
|
|
26
|
+
|
|
27
|
+
jq -e '.turn_number == 1 and .user_prompts_seen == true' "$tracker" >/dev/null
|
|
28
|
+
jq -e '.event_type == "session.prompt"
|
|
29
|
+
and .payload.turn_number == 1
|
|
30
|
+
and (.payload.input_summary | contains("UserPromptSubmit"))' \
|
|
31
|
+
"$history_file" >/dev/null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@test "turn-tracker increments turn on second user prompt" {
|
|
35
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/user-prompt-submit-turn2.json"
|
|
36
|
+
local session_id="prompt-session-002"
|
|
37
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
38
|
+
rm -f "$tracker"
|
|
39
|
+
|
|
40
|
+
turn_state_ensure_session "$session_id"
|
|
41
|
+
jq '.user_prompts_seen = true | .turn_number = 1' "$tracker" >"${tracker}.tmp" && mv "${tracker}.tmp" "$tracker"
|
|
42
|
+
|
|
43
|
+
cat "$fixture" | "${REPO_ROOT}/scripts/hooks/turn-tracker.sh" >/dev/null 2>&1
|
|
44
|
+
|
|
45
|
+
jq -e '.turn_number == 2 and .turn_tool_seq == 0' "$tracker" >/dev/null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@test "session-duration-tracker outputs additionalContext with elapsed time" {
|
|
49
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/user-prompt-submit.json"
|
|
50
|
+
local session_id="prompt-session-001"
|
|
51
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
52
|
+
rm -f "$tracker"
|
|
53
|
+
|
|
54
|
+
turn_state_ensure_session "$session_id"
|
|
55
|
+
local past_ms
|
|
56
|
+
past_ms=$(python3 -c 'import time; print(int((time.time() - 65) * 1000))' 2>/dev/null || echo 0)
|
|
57
|
+
jq --argjson start_ms "$past_ms" \
|
|
58
|
+
'.start_time_ms = $start_ms | .turn_number = 2' \
|
|
59
|
+
"$tracker" >"${tracker}.tmp" && mv "${tracker}.tmp" "$tracker"
|
|
60
|
+
|
|
61
|
+
run bash -c "cat '${fixture}' | '${REPO_ROOT}/scripts/hooks/session-duration-tracker.sh' 2>/dev/null"
|
|
62
|
+
[ "$status" -eq 0 ]
|
|
63
|
+
|
|
64
|
+
echo "$output" | jq -e \
|
|
65
|
+
'.hookSpecificOutput.hookEventName == "UserPromptSubmit"
|
|
66
|
+
and (.hookSpecificOutput.additionalContext | contains("turn 2"))
|
|
67
|
+
and (.hookSpecificOutput.additionalContext | contains("elapsed"))' >/dev/null
|
|
68
|
+
|
|
69
|
+
jq -e '(.session_duration_ms | type) == "number" and .session_duration_ms >= 60000' "$tracker" >/dev/null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@test "session_tracker_format_duration renders minutes and seconds" {
|
|
73
|
+
[ "$(session_tracker_format_duration 65000)" = "1m 5s" ]
|
|
74
|
+
}
|