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: 7a778d19578d0a29c371f4b5e8363044db91487e9703db86278944208de434d6
4
- data.tar.gz: 7a60618611f8b9b3d3dcf13385fa720dfd434c6ad3512ed5f70ff072184bbbb7
3
+ metadata.gz: ebe80aab76837ee09279a0831b344bca9072a873e48b70197868e54a7b5a6ceb
4
+ data.tar.gz: f637b4e6f460bbb982a2c3f51b49d87cb3fcaa8e6fd2c3547a694fc0f4fa70fc
5
5
  SHA512:
6
- metadata.gz: 8c0d57e79fb46d2e67ab05e34deb0737638710fdd69acafc25b7ea0b7346225251dcf450819a9d0345afb7961c2ff77bbad66de98e2db8110480b28b41457c10
7
- data.tar.gz: 12f152c83d8d3b7018dad5aaf78e053c4504fc39849dbc0b0ebca9c5bafbb0128af0db53d54f9fb4790d65530225985c8ca0353f77e988ac23587936b8322cc5
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: Check for unresolved production errors on Claude Code startup.
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"]["SessionStart"] ||= []
42
+ existing["hooks"]["UserPromptSubmit"] ||= []
43
43
 
44
- already_registered = existing["hooks"]["SessionStart"].any? do |entry|
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"]["SessionStart"] << session_start_hook(hook_command)
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" => { "SessionStart" => [ session_start_hook(hook_command) ] }
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 (SessionStart hook)"
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 session_start_hook(command)
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
 
@@ -132,6 +132,10 @@ module RailsInformant
132
132
  error.instance_variable_set(:@__rails_informant_captured, true) unless error.frozen?
133
133
  end
134
134
 
135
+ def console_mode?
136
+ defined?(Rails::Console)
137
+ end
138
+
135
139
  def server_mode?
136
140
  defined?(Rails::Server)
137
141
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-informant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.6
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel López Prat