rails-informant 0.4.6 → 0.5.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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebe80aab76837ee09279a0831b344bca9072a873e48b70197868e54a7b5a6ceb
|
|
4
|
+
data.tar.gz: f637b4e6f460bbb982a2c3f51b49d87cb3fcaa8e6fd2c3547a694fc0f4fa70fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08bf946e26795a53d035667fad63f91ccf5dda9497710a09d9e187d82ee35323ed64397b4761a8af6e81896d915df47e4a6b3f94777e5150fb3250262db6c5ba'
|
|
7
|
+
data.tar.gz: 8fe9bb913213f18310a90ff232f11c1317246b231aeec3c9afba80c4e253d017dff9e41a829d90df5beee43f9dade333eb4317c24831340b1fdeabf50e068b02
|
data/README.md
CHANGED
|
@@ -119,6 +119,13 @@ vanishing silently.
|
|
|
119
119
|
Add your own classes with `config.ignored_exceptions`; it still walks the cause chain, so
|
|
120
120
|
ignoring a class also ignores exceptions that wrap it.
|
|
121
121
|
|
|
122
|
+
### Interactive Console
|
|
123
|
+
|
|
124
|
+
Informant never captures errors raised in an interactive `rails console` session -- nothing
|
|
125
|
+
is recorded and no notifications are sent. You see exceptions live at the prompt, so
|
|
126
|
+
recording and alerting on them would only be noise. This is always on and not configurable.
|
|
127
|
+
Errors from web requests, background jobs, and rake tasks are captured as normal.
|
|
128
|
+
|
|
122
129
|
### Silenced Blocks
|
|
123
130
|
|
|
124
131
|
```ruby
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Informant:
|
|
2
|
+
# Informant: On the first Claude Code prompt of a session, check for unresolved
|
|
3
|
+
# production errors — unless that first prompt is the /informant command.
|
|
3
4
|
# Requires: curl, jq
|
|
4
5
|
# Env vars: INFORMANT_PRODUCTION_URL, INFORMANT_PRODUCTION_TOKEN
|
|
5
6
|
# INFORMANT_PRODUCTION_PATH_PREFIX (optional, default: /informant)
|
|
@@ -11,9 +12,28 @@ set -euo pipefail
|
|
|
11
12
|
[[ -z "${INFORMANT_PRODUCTION_TOKEN:-}" ]] && exit 0
|
|
12
13
|
[[ "$INFORMANT_PRODUCTION_URL" == https://* ]] || exit 0
|
|
13
14
|
|
|
14
|
-
# Silent exit if jq is not installed
|
|
15
|
+
# Silent exit if jq is not installed (needed to parse the hook payload)
|
|
15
16
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
16
17
|
|
|
18
|
+
# UserPromptSubmit delivers a JSON payload on stdin carrying session_id and prompt.
|
|
19
|
+
payload=$(cat)
|
|
20
|
+
session_id=$(printf '%s' "$payload" | jq -r '.session_id // empty' 2>/dev/null || true)
|
|
21
|
+
|
|
22
|
+
# Run at most once per session, on the first prompt: a marker keyed by session_id
|
|
23
|
+
# records that this session was handled, so later prompts short-circuit here before
|
|
24
|
+
# parsing the prompt or doing network work. Require a token-shaped session_id (it is
|
|
25
|
+
# interpolated into the path below) and stay silent when we can't record the marker,
|
|
26
|
+
# rather than re-alerting on every later prompt of the session.
|
|
27
|
+
[[ "$session_id" =~ ^[A-Za-z0-9_-]+$ ]] || exit 0
|
|
28
|
+
marker="${TMPDIR:-/tmp}/rails-informant-alert-${session_id}"
|
|
29
|
+
[[ -e "$marker" ]] && exit 0
|
|
30
|
+
: > "$marker" 2>/dev/null || exit 0
|
|
31
|
+
|
|
32
|
+
# Stay quiet for the whole session when the first prompt is the /informant command —
|
|
33
|
+
# the user is already triaging errors, so the startup alert would be redundant.
|
|
34
|
+
prompt=$(printf '%s' "$payload" | jq -r '.prompt // empty' 2>/dev/null || true)
|
|
35
|
+
[[ "$prompt" =~ ^/informant($|[[:space:]]) ]] && exit 0
|
|
36
|
+
|
|
17
37
|
path_prefix="${INFORMANT_PRODUCTION_PATH_PREFIX:-/informant}"
|
|
18
38
|
url="${INFORMANT_PRODUCTION_URL}${path_prefix}/api/v1/status"
|
|
19
39
|
|
|
@@ -25,8 +45,9 @@ response=$(curl -s -f \
|
|
|
25
45
|
"$url" <<< "Authorization: Bearer ${INFORMANT_PRODUCTION_TOKEN}" \
|
|
26
46
|
2>/dev/null) || exit 0
|
|
27
47
|
|
|
28
|
-
# Parse unresolved count
|
|
29
|
-
unresolved=$(echo "$response" | jq -r '.unresolved_count // 0') || exit 0
|
|
48
|
+
# Parse unresolved count (silent exit on a missing or non-numeric value)
|
|
49
|
+
unresolved=$(echo "$response" | jq -r '.unresolved_count // 0' 2>/dev/null) || exit 0
|
|
50
|
+
[[ "$unresolved" =~ ^[0-9]+$ ]] || exit 0
|
|
30
51
|
[[ "$unresolved" -eq 0 ]] && exit 0
|
|
31
52
|
|
|
32
53
|
# Format error summary
|
|
@@ -39,20 +39,20 @@ module RailsInformant
|
|
|
39
39
|
if File.exist?(settings_path)
|
|
40
40
|
existing = JSON.parse(File.read(settings_path))
|
|
41
41
|
existing["hooks"] ||= {}
|
|
42
|
-
existing["hooks"]["
|
|
42
|
+
existing["hooks"]["UserPromptSubmit"] ||= []
|
|
43
43
|
|
|
44
|
-
already_registered = existing["hooks"]["
|
|
44
|
+
already_registered = existing["hooks"]["UserPromptSubmit"].any? do |entry|
|
|
45
45
|
entry["hooks"]&.any? { it["command"] == hook_command }
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
unless already_registered
|
|
49
|
-
existing["hooks"]["
|
|
49
|
+
existing["hooks"]["UserPromptSubmit"] << user_prompt_submit_hook(hook_command)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
create_file ".claude/settings.json", JSON.pretty_generate(existing) + "\n", force: true
|
|
53
53
|
else
|
|
54
54
|
create_file ".claude/settings.json", JSON.pretty_generate(
|
|
55
|
-
"hooks" => { "
|
|
55
|
+
"hooks" => { "UserPromptSubmit" => [ user_prompt_submit_hook(hook_command) ] }
|
|
56
56
|
) + "\n"
|
|
57
57
|
end
|
|
58
58
|
rescue JSON::ParserError
|
|
@@ -66,7 +66,7 @@ module RailsInformant
|
|
|
66
66
|
say " Created .mcp.json"
|
|
67
67
|
say " Created .claude/skills/informant/SKILL.md"
|
|
68
68
|
say " Created .claude/hooks/informant-alerts.sh"
|
|
69
|
-
say " Created .claude/settings.json (
|
|
69
|
+
say " Created .claude/settings.json (UserPromptSubmit hook)"
|
|
70
70
|
say ""
|
|
71
71
|
say "Next step — set env vars so the MCP server and startup alerts can reach your app.", :yellow
|
|
72
72
|
say "Add to your .envrc (or export manually):"
|
|
@@ -82,9 +82,8 @@ module RailsInformant
|
|
|
82
82
|
|
|
83
83
|
private
|
|
84
84
|
|
|
85
|
-
def
|
|
85
|
+
def user_prompt_submit_hook(command)
|
|
86
86
|
{
|
|
87
|
-
"matcher" => "startup",
|
|
88
87
|
"hooks" => [
|
|
89
88
|
{ "type" => "command", "command" => command, "timeout" => 10 }
|
|
90
89
|
]
|
|
@@ -12,6 +12,9 @@ module RailsInformant
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def record(error, severity: "error", context: {}, source: nil, env: nil)
|
|
15
|
+
# Never capture from an interactive console — the operator sees errors
|
|
16
|
+
# live, so recording and alerting on them is noise.
|
|
17
|
+
return if RailsInformant.console_mode?
|
|
15
18
|
return unless RailsInformant.initialized?
|
|
16
19
|
return if self_caused_error?(error)
|
|
17
20
|
|
data/lib/rails_informant.rb
CHANGED