@onlooker-community/ecosystem 0.0.2 → 0.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -5
- package/.github/workflows/test.yml +26 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +33 -0
- package/README.md +14 -12
- package/config.json +4 -0
- package/hooks/hooks.json +46 -0
- package/mise.toml +11 -0
- package/package.json +10 -2
- package/scripts/common.sh +40 -0
- package/scripts/hooks/agent-spawn-tracker.sh +160 -0
- package/scripts/hooks/tool-history-tracker.sh +36 -0
- package/scripts/hooks/tool-sequence-tracker.sh +32 -0
- package/scripts/lib/onlooker-emit.sh +41 -0
- package/scripts/lib/onlooker-event.mjs +278 -0
- package/scripts/lib/onlooker-schema.sh +45 -0
- package/scripts/lib/tool-history.sh +35 -0
- package/scripts/lib/validate-path.sh +577 -0
- package/test/bats/agent-spawn-tracker.bats +29 -0
- package/test/bats/config.bats +67 -0
- package/test/bats/onlooker-emit.bats +26 -0
- package/test/bats/tool-history-tracker.bats +72 -0
- package/test/bats/tool-sequence-tracker.bats +53 -0
- package/test/bats/validate-path.bats +109 -0
- package/test/fixtures/hook-inputs/agent-tool.json +11 -0
- package/test/fixtures/hook-inputs/non-agent-tool.json +7 -0
- package/test/fixtures/hook-inputs/post-tool-use-failure-bash.json +12 -0
- package/test/fixtures/hook-inputs/post-tool-use-read.json +13 -0
- package/test/helpers/setup.bash +38 -0
- package/test/node/schema-events.test.mjs +67 -0
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
# shellcheck source=../../scripts/lib/onlooker-schema.sh
|
|
8
|
+
source "${REPO_ROOT}/scripts/lib/onlooker-schema.sh"
|
|
9
|
+
export _HOOK_SESSION_ID="emit-direct-session"
|
|
10
|
+
export ONLOOKER_PLUGIN_NAME="onlooker"
|
|
11
|
+
: >"$ONLOOKER_EVENTS_LOG"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@test "onlooker-emit writes canonical tool.agent.spawn to events log" {
|
|
15
|
+
local payload='{"subagent_id":"agent-99","agent_name":"explore","task_summary":"search"}'
|
|
16
|
+
"${REPO_ROOT}/scripts/lib/onlooker-emit.sh" "tool.agent.spawn" "$payload"
|
|
17
|
+
[ "$?" -eq 0 ]
|
|
18
|
+
tail -n 1 "$ONLOOKER_EVENTS_LOG" | jq -e \
|
|
19
|
+
'.schema_version == "1.0"
|
|
20
|
+
and .event_type == "tool.agent.spawn"
|
|
21
|
+
and .session_id == "emit-direct-session"
|
|
22
|
+
and .plugin == "onlooker"
|
|
23
|
+
and .payload.subagent_id == "agent-99"' \
|
|
24
|
+
>/dev/null
|
|
25
|
+
tail -n 1 "$ONLOOKER_EVENTS_LOG" | onlooker_validate_event
|
|
26
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
# shellcheck source=../../scripts/lib/onlooker-schema.sh
|
|
8
|
+
source "${REPO_ROOT}/scripts/lib/onlooker-schema.sh"
|
|
9
|
+
# shellcheck source=../../scripts/lib/tool-history.sh
|
|
10
|
+
source "${REPO_ROOT}/scripts/lib/tool-history.sh"
|
|
11
|
+
export CLAUDE_PLUGIN_ROOT="${REPO_ROOT}"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@test "tool_history_build_record returns canonical tool.file.read event" {
|
|
15
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-read.json"
|
|
16
|
+
local record
|
|
17
|
+
record=$(tool_history_build_record "$(cat "$fixture")")
|
|
18
|
+
echo "$record" | jq -e \
|
|
19
|
+
'.schema_version == "1.0"
|
|
20
|
+
and .event_type == "tool.file.read"
|
|
21
|
+
and .payload.path == "/project/src/main.ts"
|
|
22
|
+
and .session_id == "history-session-001"' \
|
|
23
|
+
>/dev/null
|
|
24
|
+
echo "$record" | onlooker_validate_event
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@test "tool_history_build_record returns canonical tool.shell.exec on failure" {
|
|
28
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-failure-bash.json"
|
|
29
|
+
local record
|
|
30
|
+
record=$(tool_history_build_record "$(cat "$fixture")")
|
|
31
|
+
echo "$record" | jq -e \
|
|
32
|
+
'.event_type == "tool.shell.exec"
|
|
33
|
+
and .payload.command == "npm test"
|
|
34
|
+
and .payload.blocked == true' \
|
|
35
|
+
>/dev/null
|
|
36
|
+
echo "$record" | onlooker_validate_event
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@test "tool-history-tracker appends canonical PostToolUse event to session JSONL" {
|
|
40
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-read.json"
|
|
41
|
+
local history_file="${ONLOOKER_SESSION_HISTORY_DIR}/history-session-001.jsonl"
|
|
42
|
+
rm -f "$history_file" "${history_file}.lock"
|
|
43
|
+
|
|
44
|
+
run bash -c "cat '${fixture}' | '${REPO_ROOT}/scripts/hooks/tool-history-tracker.sh' 2>/dev/null"
|
|
45
|
+
[ "$status" -eq 0 ]
|
|
46
|
+
[ -f "$history_file" ]
|
|
47
|
+
tail -n 1 "$history_file" | jq -e '.event_type == "tool.file.read"' >/dev/null
|
|
48
|
+
tail -n 1 "$history_file" | onlooker_validate_event
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@test "tool-history-tracker mirrors event to global onlooker-events log" {
|
|
52
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-read.json"
|
|
53
|
+
: >"$ONLOOKER_EVENTS_LOG"
|
|
54
|
+
|
|
55
|
+
cat "$fixture" | "${REPO_ROOT}/scripts/hooks/tool-history-tracker.sh" >/dev/null 2>&1
|
|
56
|
+
|
|
57
|
+
tail -n 1 "$ONLOOKER_EVENTS_LOG" | jq -e '.event_type == "tool.file.read"' >/dev/null
|
|
58
|
+
tail -n 1 "$ONLOOKER_EVENTS_LOG" | onlooker_validate_event
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@test "tool-history-tracker appends multiple canonical records for same session" {
|
|
62
|
+
local read_fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-read.json"
|
|
63
|
+
local fail_fixture="${REPO_ROOT}/test/fixtures/hook-inputs/post-tool-use-failure-bash.json"
|
|
64
|
+
local history_file="${ONLOOKER_SESSION_HISTORY_DIR}/history-session-001.jsonl"
|
|
65
|
+
rm -f "$history_file" "${history_file}.lock"
|
|
66
|
+
|
|
67
|
+
cat "$read_fixture" | "${REPO_ROOT}/scripts/hooks/tool-history-tracker.sh" >/dev/null 2>&1
|
|
68
|
+
cat "$fail_fixture" | "${REPO_ROOT}/scripts/hooks/tool-history-tracker.sh" >/dev/null 2>&1
|
|
69
|
+
|
|
70
|
+
run wc -l <"$history_file"
|
|
71
|
+
[ "$output" -eq 2 ]
|
|
72
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
}
|
|
9
|
+
|
|
10
|
+
@test "tool-sequence-tracker approves and increments turn_tool_seq" {
|
|
11
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/non-agent-tool.json"
|
|
12
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/test-session-001"
|
|
13
|
+
rm -f "$tracker"
|
|
14
|
+
|
|
15
|
+
run bash -c "cat '${fixture}' | '${REPO_ROOT}/scripts/hooks/tool-sequence-tracker.sh' 2>/dev/null"
|
|
16
|
+
[ "$status" -eq 0 ]
|
|
17
|
+
echo "$output" | jq -e '.decision == "approve"' >/dev/null
|
|
18
|
+
|
|
19
|
+
jq -e '.turn_number == 1 and .turn_tool_seq == 1' "$tracker" >/dev/null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@test "tool-sequence-tracker increments on successive tool calls" {
|
|
23
|
+
local fixture="${REPO_ROOT}/test/fixtures/hook-inputs/non-agent-tool.json"
|
|
24
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/test-session-001"
|
|
25
|
+
rm -f "$tracker"
|
|
26
|
+
|
|
27
|
+
cat "$fixture" | "${REPO_ROOT}/scripts/hooks/tool-sequence-tracker.sh" >/dev/null 2>&1
|
|
28
|
+
cat "$fixture" | "${REPO_ROOT}/scripts/hooks/tool-sequence-tracker.sh" >/dev/null 2>&1
|
|
29
|
+
|
|
30
|
+
jq -e '.turn_tool_seq == 2' "$tracker" >/dev/null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@test "turn_state_ensure_session creates tracker with defaults" {
|
|
34
|
+
local session_id="ensure-session"
|
|
35
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
36
|
+
rm -f "$tracker"
|
|
37
|
+
|
|
38
|
+
turn_state_ensure_session "$session_id"
|
|
39
|
+
[ "$?" -eq 0 ]
|
|
40
|
+
jq -e '.turn_number == 1 and .turn_tool_seq == 0' "$tracker" >/dev/null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@test "turn_state_next_tool increments existing tracker" {
|
|
44
|
+
local session_id="next-tool-session"
|
|
45
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
46
|
+
rm -f "$tracker"
|
|
47
|
+
|
|
48
|
+
turn_state_ensure_session "$session_id"
|
|
49
|
+
turn_state_next_tool "$session_id"
|
|
50
|
+
turn_state_next_tool "$session_id"
|
|
51
|
+
|
|
52
|
+
jq -e '.turn_tool_seq == 2' "$tracker" >/dev/null
|
|
53
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
# shellcheck source=../../scripts/lib/onlooker-schema.sh
|
|
8
|
+
source "${REPO_ROOT}/scripts/lib/onlooker-schema.sh"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@test "validate_file_exists succeeds for existing file" {
|
|
12
|
+
local f="${BATS_TEST_TMPDIR}/exists.txt"
|
|
13
|
+
touch "$f"
|
|
14
|
+
validate_file_exists "$f"
|
|
15
|
+
[ "$?" -eq 0 ]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@test "validate_file_exists fails for missing file" {
|
|
19
|
+
! validate_file_exists "${BATS_TEST_TMPDIR}/missing.txt"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@test "validate_dir_exists succeeds for existing directory" {
|
|
23
|
+
validate_dir_exists "${BATS_TEST_TMPDIR}"
|
|
24
|
+
[ "$?" -eq 0 ]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@test "ensure_dir_exists creates missing directory" {
|
|
28
|
+
local dir="${BATS_TEST_TMPDIR}/nested/new-dir"
|
|
29
|
+
ensure_dir_exists "$dir"
|
|
30
|
+
[ "$?" -eq 0 ]
|
|
31
|
+
[ -d "$dir" ]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@test "ensure_file_exists creates file and parent directories" {
|
|
35
|
+
local f="${BATS_TEST_TMPDIR}/deep/path/file.txt"
|
|
36
|
+
ensure_file_exists "$f"
|
|
37
|
+
[ "$?" -eq 0 ]
|
|
38
|
+
[ -f "$f" ]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@test "safe_append writes content to file" {
|
|
42
|
+
local f="${BATS_TEST_TMPDIR}/append.txt"
|
|
43
|
+
safe_append "$f" "line-one"
|
|
44
|
+
safe_append "$f" "line-two"
|
|
45
|
+
grep -q "line-one" "$f"
|
|
46
|
+
grep -q "line-two" "$f"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@test "safe_tail returns last N lines" {
|
|
50
|
+
local f="${BATS_TEST_TMPDIR}/tail.txt"
|
|
51
|
+
printf '%s\n' one two three four >"$f"
|
|
52
|
+
local result
|
|
53
|
+
result=$(safe_tail "$f" 2)
|
|
54
|
+
[ "$result" = $'three\nfour' ]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@test "hook_set_context exports session and tool from JSON" {
|
|
58
|
+
local input='{"session_id":"sess-42","tool_name":"Agent"}'
|
|
59
|
+
hook_set_context "$input" "PreToolUse"
|
|
60
|
+
[ "${ONLOOKER_HOOK_TYPE}" = "PreToolUse" ]
|
|
61
|
+
[ "${ONLOOKER_TOOL_NAME}" = "Agent" ]
|
|
62
|
+
[ "${_HOOK_SESSION_ID}" = "sess-42" ]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@test "hook_bus put/get round-trip" {
|
|
66
|
+
export _HOOK_SESSION_ID="bus-session"
|
|
67
|
+
export _HOOK_TOOL_NAME="Agent"
|
|
68
|
+
hook_bus_init '{"tool_input":{"agent_id":"1"}}'
|
|
69
|
+
hook_bus_put "scanner" '{"found":true}'
|
|
70
|
+
local result
|
|
71
|
+
result=$(hook_bus_get "scanner")
|
|
72
|
+
echo "$result" | jq -e '.found == true' >/dev/null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@test "hook_bus_has detects existing finding" {
|
|
76
|
+
export _HOOK_SESSION_ID="bus-session-2"
|
|
77
|
+
export _HOOK_TOOL_NAME="Agent"
|
|
78
|
+
hook_bus_init '{"tool_input":{"agent_id":"2"}}'
|
|
79
|
+
hook_bus_put "flag" '{"ok":true}'
|
|
80
|
+
hook_bus_has "flag"
|
|
81
|
+
[ "$?" -eq 0 ]
|
|
82
|
+
! hook_bus_has "missing"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@test "turn_state_export reads turn numbers from tracker file" {
|
|
86
|
+
local session_id="turn-test-session"
|
|
87
|
+
local tracker="${ONLOOKER_SESSION_TRACKERS_DIR}/${session_id}"
|
|
88
|
+
mkdir -p "$(dirname "$tracker")"
|
|
89
|
+
echo '{"turn_number":3,"turn_tool_seq":2}' >"$tracker"
|
|
90
|
+
turn_state_export "$session_id"
|
|
91
|
+
[ "${ONLOOKER_TURN_NUMBER}" = "3" ]
|
|
92
|
+
[ "${ONLOOKER_TURN_TOOL_SEQ}" = "2" ]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@test "safe_emit appends canonical event to onlooker events log" {
|
|
96
|
+
export _HOOK_SESSION_ID="emit-session"
|
|
97
|
+
export ONLOOKER_HOOK_TYPE="PreToolUse"
|
|
98
|
+
export ONLOOKER_TOOL_NAME="Read"
|
|
99
|
+
local payload='{"path":"/tmp/example.txt"}'
|
|
100
|
+
safe_emit "tool.file.read" "$payload"
|
|
101
|
+
[ "$?" -eq 0 ]
|
|
102
|
+
[ -f "$ONLOOKER_EVENTS_LOG" ]
|
|
103
|
+
tail -n 1 "$ONLOOKER_EVENTS_LOG" | jq -e \
|
|
104
|
+
'.event_type == "tool.file.read"
|
|
105
|
+
and .session_id == "emit-session"
|
|
106
|
+
and .payload.path == "/tmp/example.txt"
|
|
107
|
+
and .schema_version == "1.0"' \
|
|
108
|
+
>/dev/null
|
|
109
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"session_id": "history-session-001",
|
|
3
|
+
"hook_event_name": "PostToolUseFailure",
|
|
4
|
+
"tool_name": "Bash",
|
|
5
|
+
"tool_use_id": "toolu_bash_001",
|
|
6
|
+
"duration_ms": 4187,
|
|
7
|
+
"tool_input": {
|
|
8
|
+
"command": "npm test",
|
|
9
|
+
"description": "Run test suite"
|
|
10
|
+
},
|
|
11
|
+
"error": "Command exited with non-zero status code 1"
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"session_id": "history-session-001",
|
|
3
|
+
"hook_event_name": "PostToolUse",
|
|
4
|
+
"tool_name": "Read",
|
|
5
|
+
"tool_use_id": "toolu_read_001",
|
|
6
|
+
"duration_ms": 42,
|
|
7
|
+
"tool_input": {
|
|
8
|
+
"file_path": "/project/src/main.ts"
|
|
9
|
+
},
|
|
10
|
+
"tool_response": {
|
|
11
|
+
"content": "export function main() {\n return 1;\n}\n"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared setup for Onlooker ecosystem bats tests.
|
|
3
|
+
|
|
4
|
+
# Repo root: test/helpers -> test -> repo
|
|
5
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
6
|
+
export REPO_ROOT
|
|
7
|
+
|
|
8
|
+
# BATS_TEST_TMPDIR may be unset during setup_file on some runners; ensure a temp base.
|
|
9
|
+
if [[ -z "${BATS_TEST_TMPDIR:-}" ]]; then
|
|
10
|
+
export BATS_TEST_TMPDIR="${TMPDIR:-/tmp}/onlooker-bats-${BATS_SUITE_TEST_NUMBER:-$$}"
|
|
11
|
+
mkdir -p "$BATS_TEST_TMPDIR"
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Isolate all filesystem side effects under BATS_TEST_TMPDIR.
|
|
15
|
+
setup_test_env() {
|
|
16
|
+
export TEST_HOME="${BATS_TEST_TMPDIR}/home"
|
|
17
|
+
mkdir -p "$TEST_HOME"
|
|
18
|
+
|
|
19
|
+
export HOME="$TEST_HOME"
|
|
20
|
+
export ONLOOKER_DIR="${TEST_HOME}/.onlooker"
|
|
21
|
+
export CLAUDE_HOME="${TEST_HOME}/.claude"
|
|
22
|
+
export CLAUDE_PLUGIN_ROOT="${REPO_ROOT}"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Source validate-path.sh with test env vars already set.
|
|
26
|
+
load_validate_path() {
|
|
27
|
+
setup_test_env
|
|
28
|
+
# shellcheck disable=SC1091
|
|
29
|
+
source "${REPO_ROOT}/scripts/lib/validate-path.sh"
|
|
30
|
+
|
|
31
|
+
mkdir -p \
|
|
32
|
+
"$(dirname "$ONLOOKER_EVENTS_LOG")" \
|
|
33
|
+
"$ONLOOKER_SESSION_TRACKERS_DIR" \
|
|
34
|
+
"$ONLOOKER_SESSION_HISTORY_DIR" \
|
|
35
|
+
"$ONLOOKER_SESSION_SUMMARIES_DIR" \
|
|
36
|
+
"$ONLOOKER_COMPACT_TRACKERS_DIR" \
|
|
37
|
+
"$ONLOOKER_METRICS_DIR"
|
|
38
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { test } from 'node:test';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { validate } from '@onlooker-community/schema';
|
|
8
|
+
import { buildCanonicalEvent, mapHookInputToCanonical } from '../../scripts/lib/onlooker-event.mjs';
|
|
9
|
+
|
|
10
|
+
const REPO_ROOT = join(fileURLToPath(new URL('../..', import.meta.url)));
|
|
11
|
+
const FIXTURES = join(REPO_ROOT, 'test/fixtures/hook-inputs');
|
|
12
|
+
|
|
13
|
+
function loadFixture(name) {
|
|
14
|
+
return JSON.parse(readFileSync(join(FIXTURES, name), 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test('mapHookInputToCanonical maps PostToolUse Read to tool.file.read', () => {
|
|
18
|
+
const hookInput = loadFixture('post-tool-use-read.json');
|
|
19
|
+
const tmpDir = join(REPO_ROOT, 'test/tmp-schema-events');
|
|
20
|
+
const mapped = mapHookInputToCanonical(hookInput, {
|
|
21
|
+
onlookerDir: tmpDir,
|
|
22
|
+
plugin: 'onlooker',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
assert.equal(mapped.valid, true);
|
|
26
|
+
assert.equal(mapped.event.event_type, 'tool.file.read');
|
|
27
|
+
assert.equal(mapped.event.schema_version, '1.0');
|
|
28
|
+
assert.equal(mapped.event.payload.path, '/project/src/main.ts');
|
|
29
|
+
assert.equal(validate(mapped.event).valid, true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('mapHookInputToCanonical maps PostToolUseFailure Bash to tool.shell.exec', () => {
|
|
33
|
+
const hookInput = loadFixture('post-tool-use-failure-bash.json');
|
|
34
|
+
const tmpDir = join(REPO_ROOT, 'test/tmp-schema-events');
|
|
35
|
+
const mapped = mapHookInputToCanonical(hookInput, {
|
|
36
|
+
onlookerDir: tmpDir,
|
|
37
|
+
plugin: 'onlooker',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.equal(mapped.valid, true);
|
|
41
|
+
assert.equal(mapped.event.event_type, 'tool.shell.exec');
|
|
42
|
+
assert.equal(mapped.event.payload.command, 'npm test');
|
|
43
|
+
assert.equal(mapped.event.payload.blocked, true);
|
|
44
|
+
assert.equal(validate(mapped.event).valid, true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('buildCanonicalEvent assigns monotonic file-backed sequence', () => {
|
|
48
|
+
const tmpDir = mkdtempSync(join(tmpdir(), 'onlooker-seq-'));
|
|
49
|
+
const a = buildCanonicalEvent({
|
|
50
|
+
onlookerDir: tmpDir,
|
|
51
|
+
plugin: 'onlooker',
|
|
52
|
+
session_id: 'seq-test',
|
|
53
|
+
event_type: 'tool.file.read',
|
|
54
|
+
payload: { path: '/a' },
|
|
55
|
+
});
|
|
56
|
+
const b = buildCanonicalEvent({
|
|
57
|
+
onlookerDir: tmpDir,
|
|
58
|
+
plugin: 'onlooker',
|
|
59
|
+
session_id: 'seq-test',
|
|
60
|
+
event_type: 'tool.file.read',
|
|
61
|
+
payload: { path: '/b' },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
assert.equal(a.sequence, 0);
|
|
65
|
+
assert.equal(b.sequence, 1);
|
|
66
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
67
|
+
});
|