@reddb-io/red-skills 4.4.1 → 4.6.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.
Files changed (78) hide show
  1. package/bin/build-info.mjs +87 -0
  2. package/bin/cli-frontdoor.mjs +14 -0
  3. package/bin/red-skills-brain.mjs +17 -22
  4. package/bin/red-skills-content.mjs +17 -0
  5. package/bin/red-skills-hook.mjs +45 -0
  6. package/bin/red-skills-memory.mjs +17 -22
  7. package/bin/red-skills-redskilled-mcp.mjs +2 -0
  8. package/bin/red-skills-resource.mjs +21 -0
  9. package/bin/runtime-compatibility.mjs +17 -0
  10. package/bin/runtime-paths.mjs +13 -0
  11. package/dist/code-nav.bundle.min.mjs +1 -1
  12. package/dist/opencode-host.bundle.min.mjs +1 -1
  13. package/dist/redskilled-mcp.bundle.min.mjs +36 -36
  14. package/dist/redskilled-web.bundle.min.mjs +311 -0
  15. package/dist/redskilled.bundle.min.mjs +306 -292
  16. package/dist/release.bundle.min.mjs +1 -1
  17. package/dist/rsp-core.bundle.min.mjs +1 -1
  18. package/dist/rsp.bundle.min.mjs +1 -1
  19. package/dist/statusline.bundle.min.mjs +1 -1
  20. package/package.json +12 -4
  21. package/runtime/hook-routes.json +125 -0
  22. package/runtime/plugins/brain/scripts/bootstrap.mjs +656 -0
  23. package/runtime/plugins/brain/scripts/structural-smoke.sh +7 -0
  24. package/runtime/plugins/dev/hooks/branch-lock-codex.sh +105 -0
  25. package/runtime/plugins/dev/hooks/code-nav-mcp.sh +63 -0
  26. package/runtime/plugins/dev/hooks/command-guard.sh +893 -0
  27. package/runtime/plugins/dev/hooks/ensure-codex-statusline.mjs +144 -0
  28. package/runtime/plugins/dev/hooks/red-fetch.mjs +38 -0
  29. package/runtime/plugins/dev/hooks/redskilled-mcp.sh +64 -0
  30. package/runtime/plugins/dev/hooks/rsp-hook.sh +343 -0
  31. package/runtime/plugins/dev/hooks/tests/command-guard.test.sh +378 -0
  32. package/runtime/plugins/dev/hooks/tests/rsp-hook.test.sh +229 -0
  33. package/runtime/plugins/dev/scripts/memory-bridge.sh +230 -0
  34. package/runtime/plugins/dev/scripts/structural-smoke.sh +7 -0
  35. package/runtime/plugins/dev/scripts/tests/memory-bridge.test.sh +555 -0
  36. package/runtime/plugins/dev/skills/engineering/afk/defaults/cargo-pre-worktree.sh +37 -0
  37. package/runtime/plugins/dev/skills/engineering/afk/defaults/envelope-post-attempt.sh +47 -0
  38. package/runtime/plugins/dev/skills/engineering/afk/defaults/gradle-pre-worktree.sh +45 -0
  39. package/runtime/plugins/dev/skills/engineering/afk/defaults/heartbeat-post-attempt.sh +43 -0
  40. package/runtime/plugins/dev/skills/engineering/afk/defaults/validation-post-merge.sh +77 -0
  41. package/runtime/plugins/dev/skills/engineering/afk/detectors/cargo.sh +27 -0
  42. package/runtime/plugins/dev/skills/engineering/afk/detectors/gradle.sh +38 -0
  43. package/runtime/plugins/dev/skills/engineering/afk/examples/only-mine.sh +32 -0
  44. package/runtime/plugins/dev/skills/engineering/afk/examples/red-afk-attempt-action.yml +53 -0
  45. package/runtime/plugins/dev/skills/engineering/afk/examples/rs-afk-attempt.yml +76 -0
  46. package/runtime/plugins/dev/skills/engineering/afk/hooks/red-cargo +38 -0
  47. package/runtime/plugins/dev/skills/engineering/afk/hooks/red-envelope +50 -0
  48. package/runtime/plugins/dev/skills/engineering/afk/hooks/red-gradle +42 -0
  49. package/runtime/plugins/dev/skills/engineering/afk/hooks/red-heartbeat +46 -0
  50. package/runtime/plugins/dev/skills/engineering/afk/hooks/red-validation +79 -0
  51. package/runtime/plugins/dev/skills/engineering/diagnose/scripts/hitl-loop.template.sh +41 -0
  52. package/runtime/plugins/dev/skills/engineering/red-setup/scripts/install-runtime-shim.sh +181 -0
  53. package/runtime/plugins/dev/skills/engineering/red-setup/workflows/red-issues-needs-triage.yml +36 -0
  54. package/runtime/plugins/dev/skills/engineering/wizard/template.sh +211 -0
  55. package/runtime/plugins/dev/skills/engineering/zoom-out/scripts/graph-mode-plumbing.sh +36 -0
  56. package/runtime/plugins/dev/skills/engineering/zoom-out/scripts/tests/contract.test.sh +168 -0
  57. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/branch-lock-hook.sh +113 -0
  58. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/branch-lock-session-start.sh +81 -0
  59. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/branch-lock.sh +68 -0
  60. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/lib/dev-config.sh +126 -0
  61. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/lib/git-command-classifier.sh +198 -0
  62. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/lib/lock-store.sh +67 -0
  63. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/lib/scope-resolver.sh +43 -0
  64. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/branch-lock-cli.test.sh +114 -0
  65. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/claude-plugin-hook.test.sh +117 -0
  66. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/codex-hook.test.sh +230 -0
  67. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/dev-config.test.sh +99 -0
  68. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/git-command-classifier.test.sh +187 -0
  69. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/lock-store.test.sh +90 -0
  70. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/scope-resolver.test.sh +63 -0
  71. package/runtime/plugins/dev/skills/misc/branch-lock/scripts/tests/session-start.test.sh +123 -0
  72. package/runtime/plugins/dev/skills/misc/git-guardrails-claude-code/scripts/block-dangerous-git.sh +231 -0
  73. package/runtime/plugins/dev/skills/misc/git-guardrails-claude-code/scripts/tests/block-dangerous-git.test.sh +143 -0
  74. package/runtime/plugins/internal/scripts/structural-smoke.sh +7 -0
  75. package/runtime/plugins/internal/skills/maintainer/create-plugin/scripts/create-plugin.sh +308 -0
  76. package/runtime/plugins/memory/scripts/bootstrap.mjs +659 -0
  77. package/runtime/plugins/memory/scripts/structural-smoke.sh +7 -0
  78. package/scripts/check-skills-boundary.mjs +32 -0
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env bash
2
+ set -u
3
+
4
+ # Path of the drained stdin payload. The host writes the hook payload to our
5
+ # stdin *after* spawning us, so every exit path — including the fail-open ones —
6
+ # must drain stdin first; exiting with the pipe still unread makes the host's
7
+ # write fail with EPIPE.
8
+ STDIN_PAYLOAD=""
9
+ tmp=""
10
+ cleanup() {
11
+ [ -n "$STDIN_PAYLOAD" ] && rm -f "$STDIN_PAYLOAD" 2>/dev/null
12
+ return 0
13
+ }
14
+ trap cleanup EXIT
15
+
16
+ debug_enabled() {
17
+ case "${RED_SKILLS_HOOK_DEBUG:-}" in
18
+ 1|true|TRUE|yes|YES) return 0 ;;
19
+ *) return 1 ;;
20
+ esac
21
+ }
22
+
23
+ debug() {
24
+ debug_enabled || return 0
25
+ printf 'rsp-hook: %s\n' "$*" >&2
26
+ }
27
+
28
+ print_empty_json() {
29
+ printf '{}'
30
+ }
31
+
32
+ plugin_root() {
33
+ local root
34
+ for root in \
35
+ "${RED_SKILLS_DEV_PLUGIN_ROOT:-}" \
36
+ "${CLAUDE_PLUGIN_ROOT:-}" \
37
+ "${CODEX_PLUGIN_ROOT:-}" \
38
+ "${OPENCODE_PLUGIN_ROOT:-}"
39
+ do
40
+ [ -n "$root" ] || continue
41
+ printf '%s\n' "$root"
42
+ return 0
43
+ done
44
+ return 1
45
+ }
46
+
47
+ plugin_manifest() {
48
+ local root="$1" manifest
49
+ for manifest in \
50
+ "$root/.claude-plugin/plugin.json" \
51
+ "$root/.codex-plugin/plugin.json"
52
+ do
53
+ [ -f "$manifest" ] || continue
54
+ printf '%s\n' "$manifest"
55
+ return 0
56
+ done
57
+ return 1
58
+ }
59
+
60
+ plugin_manifest_for_hook() {
61
+ local root="$1" hook_name="$2" manifest
62
+ case "$hook_name" in
63
+ codex-*) manifest="$root/.codex-plugin/plugin.json" ;;
64
+ *) manifest="$root/.claude-plugin/plugin.json" ;;
65
+ esac
66
+ if [ -f "$manifest" ]; then
67
+ printf '%s\n' "$manifest"
68
+ return 0
69
+ fi
70
+ plugin_manifest "$root"
71
+ }
72
+
73
+ cache_dir() {
74
+ printf '%s\n' "${RED_SKILLS_RSP_HOOK_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/red-skills/hook-cache}"
75
+ }
76
+
77
+ cache_file() {
78
+ local root="$1" dir key
79
+ if [ -z "${RED_SKILLS_RSP_HOOK_CACHE_DIR:-}" ]; then
80
+ printf '%s/.red-skills-rsp-hook.cache\n' "$root"
81
+ return 0
82
+ fi
83
+ dir="$(cache_dir)" || return 1
84
+ key="$(printf '%s' "$root" | cksum | cut -d ' ' -f 1)" || return 1
85
+ [ -n "$key" ] || return 1
86
+ printf '%s/rsp-%s.cache\n' "$dir" "$key"
87
+ }
88
+
89
+ with_timeout() {
90
+ if command -v timeout >/dev/null 2>&1; then
91
+ timeout "${RED_SKILLS_HOOK_TIMEOUT_S:-3s}" "$@"
92
+ else
93
+ "$@"
94
+ fi
95
+ }
96
+
97
+ read_stdin_to() {
98
+ local target="$1" budget line
99
+ if command -v timeout >/dev/null 2>&1; then
100
+ timeout "${RED_SKILLS_HOOK_STDIN_TIMEOUT_S:-5s}" cat >"$target" 2>/dev/null || true
101
+ return 0
102
+ fi
103
+ # No `timeout(1)` on this box: bound the drain with bash's own read timeout
104
+ # so a host that never closes the pipe cannot hang the hook.
105
+ budget="${RED_SKILLS_HOOK_STDIN_TIMEOUT_S:-5s}"
106
+ budget="${budget%s}"
107
+ : >"$target" 2>/dev/null || return 0
108
+ while IFS= read -r -t "$budget" line || [ -n "$line" ]; do
109
+ printf '%s\n' "$line" >>"$target" 2>/dev/null || break
110
+ line=""
111
+ done
112
+ return 0
113
+ }
114
+
115
+ # Drain stdin BEFORE any fail-open decision. Idempotent: the first call wins.
116
+ drain_stdin() {
117
+ [ -z "$STDIN_PAYLOAD" ] || return 0
118
+ STDIN_PAYLOAD="$(mktemp "${TMPDIR:-/tmp}/red-skills-rsp-hook.XXXXXX" 2>/dev/null)" || STDIN_PAYLOAD=""
119
+ if [ -z "$STDIN_PAYLOAD" ]; then
120
+ # No temp file: still drain, so the writer never sees EPIPE.
121
+ read_stdin_to /dev/null
122
+ return 0
123
+ fi
124
+ read_stdin_to "$STDIN_PAYLOAD"
125
+ }
126
+
127
+ find_rsp_bundle() {
128
+ local root bundle dir latest cache_root version
129
+ for root in \
130
+ "${RED_SKILLS_DEV_PLUGIN_ROOT:-}" \
131
+ "${CLAUDE_PLUGIN_ROOT:-}" \
132
+ "${CODEX_PLUGIN_ROOT:-}" \
133
+ "${OPENCODE_PLUGIN_ROOT:-}"
134
+ do
135
+ [ -n "$root" ] || continue
136
+ for bundle in "$root/../../dist/rsp.bundle.min.mjs" "$root/dist/rsp.bundle.min.mjs"; do
137
+ [ -f "$bundle" ] || continue
138
+ printf '%s\n' "$bundle"
139
+ return 0
140
+ done
141
+ done
142
+
143
+ latest="$(
144
+ for dir in "$HOME"/.codex/plugins/cache/red-skills/dev/* "$HOME"/.claude/plugins/cache/red-skills/dev/*; do
145
+ [ -d "$dir" ] || continue
146
+ for bundle in "$dir/../../dist/rsp.bundle.min.mjs" "$dir/dist/rsp.bundle.min.mjs"; do
147
+ [ -f "$bundle" ] && printf '%s\t%s\n' "$(basename "$dir")" "$bundle"
148
+ done
149
+ done | sort -V | tail -1 | cut -f2-
150
+ )"
151
+ if [ -n "$latest" ]; then
152
+ printf '%s\n' "$latest"
153
+ return 0
154
+ fi
155
+
156
+ cache_root="${RED_SKILLS_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/red-skills/bundles}"
157
+ latest="$(
158
+ for bundle in "$cache_root"/.staging-rsp-*/node_modules/@reddb-io/red-skills/dist/rsp.bundle.min.mjs; do
159
+ [ -f "$bundle" ] || continue
160
+ dir="${bundle%/node_modules/@reddb-io/red-skills/dist/rsp.bundle.min.mjs}"
161
+ version="${dir##*/.staging-rsp-}"
162
+ printf '%s\t%s\n' "$version" "$bundle"
163
+ done | sort -V | tail -1 | cut -f2-
164
+ )"
165
+ if [ -n "$latest" ]; then
166
+ printf '%s\n' "$latest"
167
+ return 0
168
+ fi
169
+
170
+ if [ -f "$cache_root/rsp.bundle.min.mjs" ]; then
171
+ printf '%s\n' "$cache_root/rsp.bundle.min.mjs"
172
+ return 0
173
+ fi
174
+
175
+ latest="$(
176
+ for bundle in "$cache_root"/rsp-*.bundle.min.mjs; do
177
+ [ -f "$bundle" ] || continue
178
+ version="${bundle##*/rsp-}"
179
+ version="${version%.bundle.min.mjs}"
180
+ printf '%s\t%s\n' "$version" "$bundle"
181
+ done | sort -V | tail -1 | cut -f2-
182
+ )"
183
+ [ -n "$latest" ] || return 1
184
+ printf '%s\n' "$latest"
185
+ }
186
+
187
+ find_red_binary() {
188
+ local cache_root red version latest
189
+ cache_root="${RED_SKILLS_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/red-skills/bundles}"
190
+ latest="$(
191
+ for red in "$cache_root"/reddb/*/red "$cache_root"/reddb/*/red.exe; do
192
+ [ -x "$red" ] || continue
193
+ version="${red%/*}"
194
+ version="${version##*/}"
195
+ printf '%s\t%s\n' "$version" "$red"
196
+ done | sort -V | tail -1 | cut -f2-
197
+ )"
198
+ [ -n "$latest" ] || return 1
199
+ printf '%s\n' "$latest"
200
+ }
201
+
202
+ prime_cache() {
203
+ local root cache bundle red tmp manifest dir
204
+ drain_stdin
205
+ root="$(plugin_root || true)"
206
+ if [ -z "$root" ]; then
207
+ debug "prime skipped: plugin root is unset"
208
+ print_empty_json
209
+ return 0
210
+ fi
211
+
212
+ cache="$(cache_file "$root" || true)"
213
+ if [ -z "$cache" ]; then
214
+ debug "prime skipped: cache path could not be derived"
215
+ print_empty_json
216
+ return 0
217
+ fi
218
+
219
+ bundle="$(find_rsp_bundle || true)"
220
+ if [ -z "$bundle" ]; then
221
+ rm -f "$cache" 2>/dev/null || true
222
+ debug "prime skipped: rsp bundle not found"
223
+ print_empty_json
224
+ return 0
225
+ fi
226
+
227
+ red="$(find_red_binary || true)"
228
+ manifest="$(plugin_manifest "$root" || true)"
229
+ dir="${cache%/*}"
230
+ mkdir -p "$dir" 2>/dev/null || {
231
+ debug "prime skipped: cache directory is not writable"
232
+ print_empty_json
233
+ return 0
234
+ }
235
+
236
+ tmp="${cache}.$$"
237
+ {
238
+ printf 'PLUGIN_ROOT=%s\n' "$root"
239
+ printf 'PLUGIN_MANIFEST=%s\n' "$manifest"
240
+ printf 'RSP_BUNDLE=%s\n' "$bundle"
241
+ printf 'REDDB_BIN=%s\n' "$red"
242
+ } >"$tmp" 2>/dev/null && mv "$tmp" "$cache" 2>/dev/null || {
243
+ rm -f "$tmp" 2>/dev/null || true
244
+ debug "prime skipped: cache write failed"
245
+ print_empty_json
246
+ return 0
247
+ }
248
+
249
+ debug "primed cache for rsp bundle"
250
+ print_empty_json
251
+ }
252
+
253
+ load_cache() {
254
+ local cache="$1" key value
255
+ RSP_HOOK_CACHED_ROOT=""
256
+ RSP_HOOK_CACHED_MANIFEST=""
257
+ RSP_HOOK_CACHED_BUNDLE=""
258
+ RSP_HOOK_CACHED_REDDB_BIN=""
259
+
260
+ while IFS='=' read -r key value || [ -n "$key" ]; do
261
+ case "$key" in
262
+ PLUGIN_ROOT) RSP_HOOK_CACHED_ROOT="$value" ;;
263
+ PLUGIN_MANIFEST) RSP_HOOK_CACHED_MANIFEST="$value" ;;
264
+ RSP_BUNDLE) RSP_HOOK_CACHED_BUNDLE="$value" ;;
265
+ REDDB_BIN) RSP_HOOK_CACHED_REDDB_BIN="$value" ;;
266
+ esac
267
+ done <"$cache"
268
+ }
269
+
270
+ run_bundle() {
271
+ local hook_name="$1"
272
+ if [ -n "$STDIN_PAYLOAD" ]; then
273
+ with_timeout node "$RSP_HOOK_CACHED_BUNDLE" hook "$hook_name" <"$STDIN_PAYLOAD"
274
+ else
275
+ with_timeout node "$RSP_HOOK_CACHED_BUNDLE" hook "$hook_name"
276
+ fi
277
+ }
278
+
279
+ run_hook() {
280
+ local hook_name="$1" root cache manifest rc
281
+ drain_stdin
282
+ root="$(plugin_root || true)"
283
+ if [ -z "$root" ]; then
284
+ debug "$hook_name fail-open: plugin root is unset"
285
+ return 0
286
+ fi
287
+
288
+ cache="$(cache_file "$root" || true)"
289
+ if [ -z "$cache" ] || [ ! -f "$cache" ]; then
290
+ debug "$hook_name fail-open: rsp cache is missing"
291
+ return 0
292
+ fi
293
+
294
+ load_cache "$cache" || {
295
+ debug "$hook_name fail-open: rsp cache could not be read"
296
+ return 0
297
+ }
298
+
299
+ if [ "$RSP_HOOK_CACHED_ROOT" != "$root" ]; then
300
+ debug "$hook_name fail-open: rsp cache root mismatch"
301
+ return 0
302
+ fi
303
+
304
+ manifest="$(plugin_manifest_for_hook "$root" "$hook_name" || true)"
305
+ if [ -n "$manifest" ] && [ "$manifest" -nt "$cache" ]; then
306
+ debug "$hook_name fail-open: stale rsp cache"
307
+ return 0
308
+ fi
309
+
310
+ if [ -z "$RSP_HOOK_CACHED_BUNDLE" ] || [ ! -f "$RSP_HOOK_CACHED_BUNDLE" ]; then
311
+ debug "$hook_name fail-open: cached rsp bundle is missing"
312
+ return 0
313
+ fi
314
+
315
+ if [ -n "$RSP_HOOK_CACHED_REDDB_BIN" ]; then
316
+ REDDB_BIN="$RSP_HOOK_CACHED_REDDB_BIN" run_bundle "$hook_name"
317
+ rc=$?
318
+ else
319
+ run_bundle "$hook_name"
320
+ rc=$?
321
+ fi
322
+
323
+ if [ "$rc" -ne 0 ]; then
324
+ debug "$hook_name fail-open: rsp bundle exited $rc"
325
+ return 0
326
+ fi
327
+ return 0
328
+ }
329
+
330
+ case "${1:-}" in
331
+ prime)
332
+ prime_cache
333
+ ;;
334
+ claude-pre-exec|claude-post-exec|codex-pre-exec|codex-post-exec)
335
+ run_hook "$1"
336
+ ;;
337
+ *)
338
+ drain_stdin
339
+ debug "fail-open: unknown rsp hook mode '${1:-}'"
340
+ ;;
341
+ esac
342
+
343
+ exit 0