shadok-ai 0.3.105 → 0.3.106

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.
@@ -18,19 +18,69 @@ pr=${1:-}
18
18
  [ -n "$pr" ] || exit 0
19
19
  repo=${2:-shadok-ai/shadok-ai}
20
20
 
21
+ # Reads the PR JSON on stdin. `pr_field head` prints the head sha; `pr_field
22
+ # state <checks-json>` prints the same state line shape the gh path produces, so
23
+ # a state file written by one backend stays comparable with the other.
24
+ pr_field() {
25
+ python3 -c '
26
+ import json, sys
27
+ mode = sys.argv[1]
28
+ checks_raw = sys.argv[2] if len(sys.argv) > 2 else ""
29
+ try:
30
+ p = json.load(sys.stdin)
31
+ except Exception:
32
+ sys.exit(1)
33
+ if mode == "head":
34
+ print(p.get("head", {}).get("sha", ""))
35
+ sys.exit(0)
36
+ if checks_raw:
37
+ try:
38
+ runs = json.loads(checks_raw).get("check_runs", [])
39
+ checks = " ".join("%s=%s" % (c["name"], c.get("conclusion") or c.get("status")) for c in runs) or "no-checks"
40
+ except Exception:
41
+ checks = "checks-unknown"
42
+ else:
43
+ checks = "checks-unknown"
44
+ print("|".join([str(p.get("state")), str(p.get("mergeable")), str(p.get("mergeable_state") or ""), checks]))
45
+ ' "$@"
46
+ }
47
+
21
48
  state_dir="$HOME/.shadok-ai/tweak-pr"
22
49
  mkdir -p "$state_dir" 2>/dev/null || exit 0
23
50
  key=$(printf '%s' "$pr" | tr -c 'A-Za-z0-9' '-')
24
51
  state_file="$state_dir/$key.state"
25
52
 
26
- now=$(gh pr view "$pr" --repo "$repo" \
27
- --json state,mergeable,reviewDecision,statusCheckRollup \
28
- --template '{{.state}}|{{.mergeable}}|{{.reviewDecision}}|{{range .statusCheckRollup}}{{.name}}={{.conclusion}} {{end}}' \
29
- 2>/dev/null) || exit 0
30
- # gh can succeed and print nothing (rate limit, transient auth): treat as no news
31
- # rather than as "everything vanished".
53
+ now=""
54
+ if command -v gh >/dev/null 2>&1; then
55
+ now=$(gh pr view "$pr" --repo "$repo" \
56
+ --json state,mergeable,reviewDecision,statusCheckRollup \
57
+ --template '{{.state}}|{{.mergeable}}|{{.reviewDecision}}|{{range .statusCheckRollup}}{{.name}}={{.conclusion}} {{end}}' \
58
+ 2>/dev/null) || exit 0
59
+ else
60
+ # No gh on this host. Falling through to `|| exit 0` would leave the guard
61
+ # PERMANENTLY silent — it would pass the "prints nothing, exits 0" check while
62
+ # never being able to fire, which reads as coverage and is worse than no watch
63
+ # at all. The public API answers the same questions without any credential.
64
+ api="https://api.github.com/repos/$repo"
65
+ body=$(curl -sf --max-time 20 "$api/pulls/$pr" 2>/dev/null) || exit 0
66
+ [ -n "$body" ] || exit 0
67
+ head=$(printf '%s' "$body" | pr_field head 2>/dev/null) || exit 0
68
+ [ -n "$head" ] || exit 0
69
+ checks=$(curl -sf --max-time 20 "$api/commits/$head/check-runs" 2>/dev/null) || checks=""
70
+ now=$(printf '%s' "$body" | pr_field state "$checks" 2>/dev/null) || exit 0
71
+ fi
72
+ # A backend can succeed and print nothing (rate limit, transient auth): treat as
73
+ # no news rather than as "everything vanished".
32
74
  [ -n "$now" ] || exit 0
33
75
 
76
+ # GitHub computes mergeability lazily and answers UNKNOWN/null meanwhile. Left
77
+ # alone, UNKNOWN -> MERGEABLE -> UNKNOWN wakes the agent three times for one
78
+ # non-event, so a still-computing slot is skipped rather than reported.
79
+ case "$now" in
80
+ *"|UNKNOWN|"*|*"|None|"*) exit 0 ;;
81
+ *checks-unknown) exit 0 ;;
82
+ esac
83
+
34
84
  prev=""
35
85
  [ -f "$state_file" ] && prev=$(cat "$state_file" 2>/dev/null)
36
86
 
@@ -62,6 +62,11 @@ you are woken only when its state, mergeability, review decision or CI result
62
62
  actually changes. Run the guard once by hand before registering: it must print
63
63
  nothing and exit 0. A guard that writes to stderr wakes you every five minutes.
64
64
 
65
+ Silence alone does not prove it works — an inert guard is silent too. Run it
66
+ twice against a PR whose state you know, and check that
67
+ `~/.shadok-ai/tweak-pr/*.state` now holds a line. No state file means it never
68
+ reached GitHub, and the watch will never fire.
69
+
65
70
  When you are woken:
66
71
 
67
72
  - **CI red, or the branch behind `main`** — fix it and push. Read the failing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.3.105",
3
+ "version": "0.3.106",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts .claude/skills/shadok-ai-agents/test/*.test.mjs context/*/test/*.test.mjs",