rails-informant 0.4.7 → 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: e1238247be3c3dcefa39e50f4907cd23f9e10282fe32cbf480c2bb4d5edd1daa
4
- data.tar.gz: 51df461568d6e54a3860c52d552f5d365531c65f80005ba025facb0b3ee54e13
3
+ metadata.gz: ebe80aab76837ee09279a0831b344bca9072a873e48b70197868e54a7b5a6ceb
4
+ data.tar.gz: f637b4e6f460bbb982a2c3f51b49d87cb3fcaa8e6fd2c3547a694fc0f4fa70fc
5
5
  SHA512:
6
- metadata.gz: 02c696395075fd1bfc4b895a916812c512797c64b2031f5d03110b1c636de066043ff26c562112056af1f961da0dffea0e2d6409b1bd5ace298b2f2d7d09ec9d
7
- data.tar.gz: 1e1c83d7898f5f7f96c9ad4d07682feb67cba4dc915a119d4cc16cda3035b0c7cfae5e890f7479c8593116aaa09ee416d23cfb6a0e0335a972957853f8c9bebe
6
+ metadata.gz: '08bf946e26795a53d035667fad63f91ccf5dda9497710a09d9e187d82ee35323ed64397b4761a8af6e81896d915df47e4a6b3f94777e5150fb3250262db6c5ba'
7
+ data.tar.gz: 8fe9bb913213f18310a90ff232f11c1317246b231aeec3c9afba80c4e253d017dff9e41a829d90df5beee43f9dade333eb4317c24831340b1fdeabf50e068b02
@@ -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
  ]
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.7
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel López Prat