ruvnet-brain 4.0.12 → 4.0.24

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 (45) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/plugin/.claude-plugin/plugin.json +2 -2
  4. package/plugin/.codex-plugin/plugin.json +1 -1
  5. package/plugin/scripts/advocacy-outcomes.mjs +808 -0
  6. package/plugin/scripts/anticipate.sh +80 -14
  7. package/plugin/scripts/capability-registry.mjs +994 -0
  8. package/plugin/scripts/codex-hook-wrapper.mjs +1 -0
  9. package/plugin/scripts/continuation-gate.mjs +129 -1
  10. package/plugin/scripts/gates.mjs +146 -0
  11. package/plugin/scripts/goal-match.mjs +398 -0
  12. package/plugin/scripts/hijack-ruvnet.sh +69 -1
  13. package/plugin/scripts/hook-registry.mjs +616 -0
  14. package/plugin/scripts/hook-shim.mjs +13 -2
  15. package/plugin/scripts/learning-enable.mjs +382 -0
  16. package/plugin/scripts/lesson-promote.mjs +262 -0
  17. package/plugin/scripts/lesson-provenance.mjs +43 -0
  18. package/plugin/scripts/lesson-store.mjs +67 -56
  19. package/plugin/scripts/memory-doctor.mjs +345 -0
  20. package/plugin/scripts/nightly-controller.mjs +98 -0
  21. package/plugin/scripts/runtime-preferences.mjs +18 -0
  22. package/plugin/scripts/unprompted-runtime.mjs +22 -7
  23. package/plugin/scripts/user-settings.mjs +672 -0
  24. package/plugin/skills/ruvnet-brain/SKILL.md +2 -2
  25. package/scripts/advocacy-outcomes.mjs +4 -808
  26. package/scripts/capability-registry.mjs +4 -876
  27. package/scripts/corpus-qa.mjs +44 -6
  28. package/scripts/doc-currency.mjs +30 -2
  29. package/scripts/gates.mjs +4 -146
  30. package/scripts/goal-match.mjs +4 -398
  31. package/scripts/hook-registry.mjs +4 -567
  32. package/scripts/issue-watch.mjs +108 -0
  33. package/scripts/learning-enable.mjs +4 -380
  34. package/scripts/lesson-promote.mjs +4 -262
  35. package/scripts/memory-doctor.mjs +4 -345
  36. package/scripts/nightly-controller.mjs +4 -66
  37. package/scripts/nightly-wrapper.sh +23 -1
  38. package/scripts/proactivity-metrics.mjs +8 -1
  39. package/scripts/qe/ux-suite.mjs +72 -1
  40. package/scripts/release-abort-stale.mjs +111 -0
  41. package/scripts/release-convergence-watchdog.mjs +119 -0
  42. package/scripts/release-transaction-provider.mjs +46 -6
  43. package/scripts/release-transaction.mjs +55 -17
  44. package/scripts/self-update.mjs +63 -10
  45. package/scripts/user-settings.mjs +4 -640
@@ -64,28 +64,67 @@ set +e
64
64
  SELF_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" 2>/dev/null && pwd)
65
65
  [ -n "$SELF_DIR" ] || exit 0
66
66
 
67
- # <codeRoot>/plugin/scripts/anticipate.sh → <codeRoot>. Resolved from THIS file's own location, so
68
- # it is correct under the Stable Spine (an immutable ~/.cache/ruvnet-brain/versions/<gen> tree) and
69
- # in a dev checkout alike, without reading active.json — hook-shim.mjs has already chosen the tree
70
- # by the time it executes this body.
71
- CODE_ROOT=$(CDPATH='' cd -- "$SELF_DIR/../.." 2>/dev/null && pwd)
72
- [ -n "$CODE_ROOT" ] || exit 0
67
+ # WHERE THE THREE MODULES LIVE — resolved by PROBE, not by assertion (2026-08-04).
68
+ #
69
+ # This block used to be one line — `CODE_ROOT=$SELF_DIR/../..` — justified by the claim, repeated in
70
+ # the ADVOCACY_MODULE comment below, that a dev checkout and the Stable Spine "both keep `scripts/`
71
+ # as a sibling of `plugin/`". MEASURED on a real install, that is FALSE in both shipped layouts, and
72
+ # true only in the one layout that never reaches a user:
73
+ #
74
+ # <plugin-cache>/ruvnet-brain/4.0.7/scripts/anticipate.sh → ../.. = <plugin-cache>/ruvnet-brain
75
+ # ~/.cache/ruvnet-brain/versions/<gen>/scripts/anticipate.sh → ../.. = .../versions
76
+ # <src>/plugin/scripts/anticipate.sh → ../.. = <src> ← only this
77
+ #
78
+ # Both distribution channels FLATTEN the `plugin/` level, so `../..` overshoots by one directory and
79
+ # $CODE_ROOT/scripts/goal-match.mjs never existed. The `[ -f "$GOAL_MATCH" ] || exit 0` guard below
80
+ # then did exactly what it promises — it stayed silent — so the L4 surface shipped permanently and
81
+ # INVISIBLY inert. A hook whose only failure mode is silence cannot report its own breakage; that is
82
+ # precisely why this needs a probe and not a comment.
83
+ #
84
+ # THE FIX IS TO ASK THE FILESYSTEM. Try each candidate directory and take the first that actually
85
+ # holds the matcher. That is the same discipline the rest of this file already applies to the
86
+ # machine's state: never render an assumption as a fact. Candidates, in order:
87
+ #
88
+ # 1. $SELF_DIR — modules shipped as SIBLINGS of this script (the flattened plugin
89
+ # zip and the Stable Spine, once packaging ships them; see below)
90
+ # 2. $SELF_DIR/../../scripts — the source/dev layout <src>/plugin/scripts → <src>/scripts
91
+ # 3. $SELF_DIR/../scripts — a root that keeps scripts/ one level up from this file
92
+ #
93
+ # PACKAGING IS THE OTHER HALF, and neither half works alone. goal-match.mjs, capability-registry.mjs
94
+ # and advocacy-outcomes.mjs currently live ONLY in the repo-root `scripts/`, which the plugin zip
95
+ # does not carry; this resolver finds nothing until they are shipped into `plugin/scripts/` beside
96
+ # this file. Fixing the path without the packaging leaves it silent, and vice versa.
97
+ #
98
+ # If NO candidate holds the matcher we deliberately fall through to the historical path, so the
99
+ # "missing module" diagnostics below still name the location a maintainer would expect — and the
100
+ # no-node fast path keeps this hook free. Silence on doubt, never a guess: rule 4, unchanged.
101
+ resolve_module_dir() {
102
+ for _cand in "$SELF_DIR" "$SELF_DIR/../../scripts" "$SELF_DIR/../scripts"; do
103
+ _r=$(CDPATH='' cd -- "$_cand" 2>/dev/null && pwd) || continue
104
+ if [ -n "$_r" ] && [ -f "$_r/goal-match.mjs" ]; then printf '%s' "$_r"; return 0; fi
105
+ done
106
+ _r=$(CDPATH='' cd -- "$SELF_DIR/../.." 2>/dev/null && pwd) || return 1
107
+ [ -n "$_r" ] && printf '%s' "$_r/scripts"
108
+ }
109
+ MODULE_DIR=$(resolve_module_dir)
110
+ [ -n "$MODULE_DIR" ] || exit 0
73
111
 
74
112
  # All THREE module paths are env-overridable, matching the RUVNET_LESSON_STORE / RUVNET_SETTINGS_FILE
75
113
  # idiom already used across this repo — so tests never load the real registry or touch a real user's
76
114
  # state, and a future relocation needs no edit here.
77
- GOAL_MATCH="${RUVNET_GOAL_MATCH:-$CODE_ROOT/scripts/goal-match.mjs}"
78
- CAP_REGISTRY="${RUVNET_CAPABILITY_REGISTRY:-$CODE_ROOT/scripts/capability-registry.mjs}"
115
+ GOAL_MATCH="${RUVNET_GOAL_MATCH:-$MODULE_DIR/goal-match.mjs}"
116
+ CAP_REGISTRY="${RUVNET_CAPABILITY_REGISTRY:-$MODULE_DIR/capability-registry.mjs}"
79
117
  # THE SINGLE SUPPRESSION POLICY (2026-07-23). Until this build this file decided "is X suppressed"
80
118
  # with its OWN local dismissed-Set in anticipate-state.json — one dismissal muted forever, no
81
119
  # severity, no budget — while advocacy-outcomes.mjs's shouldStillOffer()/DISMISSAL_BUDGET (a nag dies
82
120
  # on 1 dismissal, a high-severity finding needs 3, with a state-change reprieve) sat completely
83
121
  # uncalled. Two thresholds for one decision is the exact hazard named below for the confidence floor;
84
122
  # the fix is the same shape — wire this module the IDENTICAL env-var-with-a-default way as the two
85
- # above, NOT a hardcoded `../scripts` path, so it resolves correctly whether this file runs from a dev
86
- # checkout or the Stable Spine's `<gen>/plugin/scripts/anticipate.sh` (both keep `scripts/` as a
87
- # sibling of `plugin/`, per this file's own CODE_ROOT comment above).
88
- ADVOCACY_MODULE="${RUVNET_ADVOCACY_OUTCOMES_MODULE:-$CODE_ROOT/scripts/advocacy-outcomes.mjs}"
123
+ # above, NOT a hardcoded `../scripts` path, so it resolves wherever this file actually runs from.
124
+ # (CORRECTED 2026-08-04: this comment previously asserted that a dev checkout and the Spine "both
125
+ # keep `scripts/` as a sibling of `plugin/`". They do not — see the measured table above. The three
126
+ # modules now resolve through MODULE_DIR, which probes rather than assumes.)
127
+ ADVOCACY_MODULE="${RUVNET_ADVOCACY_OUTCOMES_MODULE:-$MODULE_DIR/advocacy-outcomes.mjs}"
89
128
 
90
129
  # ── Subcommands (dismiss/undismiss/status) run the same node program in a different mode ─────────
91
130
  MODE="suggest"
@@ -525,10 +564,37 @@ NODE_PID=$!
525
564
  # 5s hook budget that ground-ruvnet.sh has already partly spent. A SIGKILL mid-write can at worst
526
565
  # truncate one advisory line — it can never fail the turn, and the state file was already committed
527
566
  # by then (see the persist-first ordering above).
528
- ( sleep 2; kill -9 "$NODE_PID" 2>/dev/null ) >/dev/null 2>&1 &
567
+ # THE SLEEP MUST BE OURS TO KILL (2026-08-06). This block used to be:
568
+ #
569
+ # ( sleep 2; kill -9 "$NODE_PID" 2>/dev/null ) &
570
+ # WATCHDOG_PID=$!
571
+ # wait "$NODE_PID"; kill "$WATCHDOG_PID"
572
+ #
573
+ # `kill` signals the SUBSHELL. The `sleep` it forked is a separate process this script never had a
574
+ # handle on, so it was simply ORPHANED and kept running for the remainder of its 2 seconds.
575
+ # selfcheck.mjs measures exactly that (§5 PROCESS-TREE HYGIENE, WATCHDOG_GRACE_MS = 2000) and
576
+ # reported it in BOTH the [valid] and [held] regimes as
577
+ # "left descendants alive after SIGTERM to its process group".
578
+ #
579
+ # It is deterministic on Linux rather than flaky because the watchdog's lifetime and the grace
580
+ # window are the SAME 2000ms, and the sleep starts marginally after the clock the checker uses — so
581
+ # it always outlives the probe by the spawn delta. macOS passes; ubuntu fails every time.
582
+ #
583
+ # It had never fired before because it was UNREACHABLE. Until the payload boundary was fixed
584
+ # (ADR-065) the `[ -f "$GOAL_MATCH" ] || exit 0` guard above returned first on every real install, so
585
+ # this line only ever ran in a dev checkout. Making L4 work is what woke it up — the fix did not
586
+ # create this leak, it revealed one that had been shipping dormant.
587
+ #
588
+ # FIX: fork the sleep as OUR OWN child so we hold its pid, and reap both. A `trap` inside the
589
+ # subshell was tried first and MEASURED WORSE (it defeats the shell's exec optimisation and leaked
590
+ # where the original did not) — hence the explicit two-pid form rather than anything cleverer.
591
+ sleep 2 &
592
+ SLEEP_PID=$!
593
+ ( wait "$SLEEP_PID" 2>/dev/null && kill -9 "$NODE_PID" 2>/dev/null ) >/dev/null 2>&1 &
529
594
  WATCHDOG_PID=$!
530
595
  wait "$NODE_PID" 2>/dev/null
531
- kill "$WATCHDOG_PID" 2>/dev/null
596
+ kill "$SLEEP_PID" "$WATCHDOG_PID" 2>/dev/null
597
+ wait "$SLEEP_PID" "$WATCHDOG_PID" 2>/dev/null
532
598
 
533
599
  # ALWAYS. Every failure above already routed to silence; this makes the guarantee unconditional.
534
600
  exit 0