ruvnet-brain 3.9.134-dev → 4.0.2
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.
- package/.claude-plugin/marketplace.json +14 -0
- package/README.md +5 -5
- package/bin/install.mjs +382 -36
- package/console/CONTRACT.md +172 -0
- package/console/activity.js +753 -0
- package/console/app.js +4189 -0
- package/console/architecture.html +1221 -0
- package/console/assets/depth-1.webp +0 -0
- package/console/assets/depth-2.webp +0 -0
- package/console/assets/depth-3.webp +0 -0
- package/console/assets/harness-vs-plain.svg +259 -0
- package/console/assets/hero.webp +0 -0
- package/console/assets/memory.webp +0 -0
- package/console/assets/metaharness.svg +247 -0
- package/console/index.html +777 -0
- package/console/install-architecture.html +162 -0
- package/console/install-mockup.html +543 -0
- package/console/style.css +2144 -0
- package/console/tips.css +926 -0
- package/console/tips.html +858 -0
- package/console/tips.js +128 -0
- package/docs/RELEASE-NOTES-4.0.md +88 -0
- package/kb/model-requirements.mjs +37 -6
- package/kb/zip-extract.mjs +53 -14
- package/keys/ruvnet-brain-signing.pub.pem +3 -0
- package/package.json +14 -22
- package/plugin/.claude-plugin/marketplace.json +14 -0
- package/plugin/.claude-plugin/plugin.json +22 -0
- package/plugin/.codex-plugin/plugin.json +21 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/commands/brain-console.md +16 -0
- package/plugin/commands/configure.md +33 -0
- package/plugin/commands/rvbc.md +79 -0
- package/plugin/commands/rvcb.md +16 -0
- package/plugin/commands/whats-new.md +57 -0
- package/plugin/hooks/codex-hooks.json +160 -0
- package/plugin/hooks/hook-contracts.json +77 -0
- package/plugin/hooks/hooks.json +202 -0
- package/plugin/mcp/managed-cli-interface.mjs +47 -4
- package/plugin/mcp/server.mjs +56 -6
- package/plugin/scripts/anticipate.sh +534 -0
- package/plugin/scripts/codex-hook-adapter.mjs +96 -0
- package/plugin/scripts/continuation-gate.mjs +267 -0
- package/plugin/scripts/design-wall.sh +137 -0
- package/plugin/scripts/detach.mjs +182 -0
- package/plugin/scripts/first-session-worker.mjs +38 -0
- package/plugin/scripts/gate-receipt.sh +35 -0
- package/plugin/scripts/ground-before-write.sh +199 -0
- package/plugin/scripts/ground-ruvnet.sh +517 -0
- package/plugin/scripts/grounding-stamp.sh +113 -0
- package/plugin/scripts/grounding-substance.mjs +595 -0
- package/plugin/scripts/hijack-ruvnet.sh +81 -0
- package/plugin/scripts/hook-input.mjs +558 -0
- package/plugin/scripts/hook-shim-bash.mjs +55 -0
- package/plugin/scripts/hook-shim.mjs +303 -0
- package/plugin/scripts/host-update.mjs +58 -0
- package/plugin/scripts/kling-preflight.sh +146 -0
- package/plugin/scripts/learn-capture.sh +173 -0
- package/plugin/scripts/learn-flush.mjs +155 -0
- package/plugin/scripts/lesson-hooks.sh +213 -0
- package/plugin/scripts/md-stamp.mjs +219 -0
- package/plugin/scripts/protect-brain-state.sh +84 -0
- package/plugin/scripts/route-dispatch.sh +147 -0
- package/plugin/scripts/routing-outcome-capture.mjs +89 -0
- package/plugin/scripts/runtime-preferences.mjs +269 -0
- package/plugin/scripts/session-start-core.mjs +477 -0
- package/plugin/scripts/session-start.sh +13 -0
- package/plugin/scripts/signal-watch.mjs +193 -0
- package/plugin/scripts/unprompted-runtime.mjs +377 -0
- package/plugin/scripts/update-apply.mjs +419 -0
- package/plugin/scripts/verify-interface.sh +53 -0
- package/plugin/scripts/version-bump-gate.sh +112 -0
- package/plugin/skills/brain-build/SKILL.md +123 -0
- package/plugin/skills/brain-console/SKILL.md +22 -0
- package/plugin/skills/brain-prompt/SKILL.md +83 -0
- package/plugin/skills/brain-score/SKILL.md +101 -0
- package/plugin/skills/release-proof/SKILL.md +81 -0
- package/plugin/skills/release-proof/agents/openai.yaml +4 -0
- package/plugin/skills/release-proof/references/receipt-contract.md +38 -0
- package/plugin/skills/release-proof/scripts/release-proof.mjs +210 -0
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +121 -0
- package/plugin/skills/ruvnet-brain/SKILL.md +234 -0
- package/plugin/skills/rvbc/SKILL.md +23 -0
- package/plugin/skills/savings/SKILL.md +46 -0
- package/plugin/skills/whats-new/SKILL.md +22 -0
- package/scripts/adr-backfill.mjs +107 -0
- package/scripts/advocacy-outcomes.mjs +808 -0
- package/scripts/agentdb-context.mjs +216 -0
- package/scripts/agentdb-fleet-doctor.mjs +101 -0
- package/scripts/ascii-drift.mjs +236 -0
- package/scripts/behavioral-l1-l4.mjs +210 -0
- package/scripts/brain-capability-check.mjs +72 -0
- package/scripts/brain-grade-groundtruth.mjs +100 -0
- package/scripts/brain-latency-50.mjs +227 -0
- package/scripts/brain-novice-50.mjs +189 -0
- package/scripts/brain-stamp.mjs +94 -0
- package/scripts/brain-state.mjs +212 -0
- package/scripts/build-bundle.mjs +522 -0
- package/scripts/build-concepts.mjs +132 -0
- package/scripts/build-l2.mjs +71 -0
- package/scripts/build-primer.mjs +73 -0
- package/scripts/build-symbols.mjs +68 -0
- package/scripts/calibrate-router.mjs +97 -0
- package/scripts/capability-audit.mjs +321 -0
- package/scripts/capability-registry.mjs +876 -0
- package/scripts/check-indexation.mjs +108 -0
- package/scripts/check-legibility.mjs +189 -0
- package/scripts/ci/build-fixture-kb.mjs +67 -0
- package/scripts/ci/learning-replay-codex-adapter.mjs +62 -0
- package/scripts/ci/learning-replay-recorder.mjs +59 -0
- package/scripts/ci/mutate-hook-timeout.mjs +70 -0
- package/scripts/ci/stranger-fixture-stage.mjs +17 -0
- package/scripts/ci/stranger-scenario.mjs +228 -0
- package/scripts/ci/stranger-timeout.mjs +25 -0
- package/scripts/ci-verdict.mjs +29 -0
- package/scripts/claims-verify.mjs +710 -0
- package/scripts/clear-claude-tmp.sh +31 -0
- package/scripts/console-engine.mjs +434 -0
- package/scripts/console-engine.test.mjs +125 -0
- package/scripts/corpus-qa.mjs +250 -0
- package/scripts/correction-detect-embed.mjs +346 -0
- package/scripts/correction-detect-measure.mjs +270 -0
- package/scripts/correction-detect.mjs +686 -0
- package/scripts/count-chunks.mjs +54 -0
- package/scripts/described-questions.json +30 -0
- package/scripts/design-grade.mjs +58 -0
- package/scripts/dev-plugin-link.sh +105 -0
- package/scripts/distill-project.mjs +200 -0
- package/scripts/doc-currency.mjs +801 -0
- package/scripts/eval-brain.mjs +244 -0
- package/scripts/fix-metaharness-memretrieve.mjs +121 -0
- package/scripts/full-hints.mjs +87 -0
- package/scripts/gate.sh +39 -0
- package/scripts/gates.mjs +146 -0
- package/scripts/gen-console-images.mjs +54 -0
- package/scripts/gen-images.mjs +47 -0
- package/scripts/git-clone-refresh.mjs +52 -0
- package/scripts/git-hooks/pre-push +126 -0
- package/scripts/goal-match.mjs +398 -0
- package/scripts/goldie-research.mjs +223 -0
- package/scripts/goldie-weekly.sh +67 -0
- package/scripts/health-repair.mjs +250 -0
- package/scripts/helix-scenario-questions.json +10 -0
- package/scripts/ingest-gists.mjs +230 -0
- package/scripts/ingest-meeting.mjs +115 -0
- package/scripts/ingest-repo.mjs +79 -0
- package/scripts/install-npx-witness.sh +49 -0
- package/scripts/issue-fix.mjs +639 -0
- package/scripts/issue-watch.mjs +276 -0
- package/scripts/issue4-close-note.md +31 -0
- package/scripts/key-canary.mjs +91 -0
- package/scripts/latency-to-surface.mjs +233 -0
- package/scripts/learning-enable.mjs +380 -0
- package/scripts/learning-replay.mjs +1570 -0
- package/scripts/learnings.mjs +62 -0
- package/scripts/lesson-gate.mjs +680 -0
- package/scripts/lesson-lifecycle.mjs +449 -0
- package/scripts/lesson-promote.mjs +262 -0
- package/scripts/lesson-ratify.mjs +98 -0
- package/scripts/lesson-seed.mjs +252 -0
- package/scripts/lesson-store.mjs +447 -0
- package/scripts/loop-checkpoint.mjs +86 -0
- package/scripts/memdb-health.sh +14 -0
- package/scripts/memory-doctor.mjs +271 -0
- package/scripts/model-catalog.mjs +79 -0
- package/scripts/nightly-controller.mjs +66 -0
- package/scripts/nightly-gists.sh +72 -0
- package/scripts/nightly-wrapper.sh +180 -0
- package/scripts/notify.sh +12 -0
- package/scripts/npx-witness.sh +56 -0
- package/scripts/onboarding-console.mjs +2749 -0
- package/scripts/private-fence.mjs +69 -0
- package/scripts/proactivity-metrics.mjs +118 -0
- package/scripts/proof-questions.json +56 -0
- package/scripts/prove.mjs +95 -0
- package/scripts/proxy/claude-proxied.sh +57 -0
- package/scripts/proxy/proxy-revert.sh +59 -0
- package/scripts/proxy/proxy-up.sh +60 -0
- package/scripts/proxy/proxy-verify.mjs +142 -0
- package/scripts/published-surface-probe.mjs +241 -0
- package/scripts/qe/card-lane-gate.mjs +162 -0
- package/scripts/qe/session-start-gate.mjs +229 -0
- package/scripts/qe/ux-suite.mjs +323 -0
- package/scripts/reconcile-project.mjs +0 -0
- package/scripts/record-lesson.mjs +113 -0
- package/scripts/refresh-model-catalog.mjs +99 -0
- package/scripts/release-proof.mjs +9 -0
- package/scripts/release-vector.mjs +281 -0
- package/scripts/release.mjs +395 -0
- package/scripts/remedy-registry.mjs +247 -0
- package/scripts/rerank-cap-eval.mjs +265 -0
- package/scripts/rerank-cap-warm-ab.mjs +129 -0
- package/scripts/route-cheap.mjs +20 -15
- package/scripts/router-utilization.mjs +182 -0
- package/scripts/routing-flywheel.mjs +596 -0
- package/scripts/rvf-generation.mjs +104 -0
- package/scripts/rvf-index-audit.mjs +138 -0
- package/scripts/self-update.mjs +508 -0
- package/scripts/selfcheck.mjs +7 -1
- package/scripts/sign-bundle.mjs +69 -0
- package/scripts/signal-watch.mjs +171 -0
- package/scripts/stack-sync.mjs +469 -0
- package/scripts/stamp-existing-rvf-generations.mjs +53 -0
- package/scripts/stamp-sweep.mjs +144 -0
- package/scripts/status-honesty.mjs +102 -0
- package/scripts/sync-version.mjs +217 -0
- package/scripts/token-report.mjs +102 -0
- package/scripts/top100-benchmark.mjs +479 -0
- package/scripts/top100-corpus.mjs +112 -0
- package/scripts/top100-semantic-assertions.mjs +449 -0
- package/scripts/update-apply.mjs +9 -0
- package/scripts/upgrade-notice.mjs +14 -0
- package/scripts/verify-bundle.mjs +51 -0
- package/scripts/verify-channels.mjs +184 -0
- package/scripts/verify-model-catalog.mjs +104 -0
- package/scripts/verify-nightly-close-issue4.sh +31 -0
- package/scripts/version.mjs +40 -0
- package/scripts/wired-check.mjs +864 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "RvBC — RuvNet Brain Console. Opens the live console page: your whole RuvNet stack on one page — what's installed, what your AI learned, one-click reversible fixes. Read-only until you click. (Also: /rvcb, /brain-console — all the same thing.)"
|
|
3
|
+
updated: 2026-07-20
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Launch the **RuvNet Brain Console** for the user. Same console as `/ruvnet-brain:configure`,
|
|
7
|
+
`/rvcb`, and `/brain-console` — every spelling lands here, so never tell the user they typed it wrong.
|
|
8
|
+
|
|
9
|
+
## The contract you are keeping
|
|
10
|
+
|
|
11
|
+
The page **opens immediately and scans itself while they watch.** The server never blocks: a cold or
|
|
12
|
+
new-project read is answered in milliseconds with "measuring…", the page keeps its skeletons and
|
|
13
|
+
narrates the wait, and each card fills in as its own measurement lands. A chip in the header says how
|
|
14
|
+
old the picture is and re-measures when clicked.
|
|
15
|
+
|
|
16
|
+
So there is nothing to wait for and nothing to warn them about. **Your entire job is: say one
|
|
17
|
+
sentence, start the server in the background, hand over the URL, and get out of the way.**
|
|
18
|
+
|
|
19
|
+
## 1. SPEAK FIRST — one short sentence, before any tool call
|
|
20
|
+
|
|
21
|
+
Your FIRST output — before any tool call, any file read, any search — is one warm line saying you are
|
|
22
|
+
opening it now and it will scan itself live in their browser. Something in the spirit of:
|
|
23
|
+
|
|
24
|
+
> "Opening your console now — it'll come up right away and scan your setup live while you watch."
|
|
25
|
+
|
|
26
|
+
Say it like a person, not a status bar. **Do not** promise 20 seconds, a minute, or any duration: the
|
|
27
|
+
page carries its own timing now, and a number invented here is a number the page will contradict.
|
|
28
|
+
|
|
29
|
+
## 2. Find the installed runtime
|
|
30
|
+
|
|
31
|
+
Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
32
|
+
A current-repository copy is allowed only in an explicit developer checkout. Never guess a
|
|
33
|
+
`~/Code/ruvnet-brain` path: the installer persists this runtime for clean users.
|
|
34
|
+
|
|
35
|
+
## 3. Start it in the BACKGROUND and open the browser
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node <repo>/scripts/onboarding-console.mjs --serve --open
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**`run_in_background: true`, ALWAYS — never in the foreground.** This is a server: it does not exit,
|
|
42
|
+
so a foreground run hangs the tool call until the 120-second timeout and turns an instant page into
|
|
43
|
+
two minutes of dead air. It binds `127.0.0.1` only and prints `http://127.0.0.1:7411/` within about a
|
|
44
|
+
third of a second.
|
|
45
|
+
|
|
46
|
+
**Then post the URL immediately.** Do not poll the log, do not wait for a scan, do not check whether
|
|
47
|
+
the data has landed — the page reports its own progress and none of it is visible from here.
|
|
48
|
+
|
|
49
|
+
**If it reports it is already running**, that is a success, not an error: open the URL yourself with
|
|
50
|
+
`open "http://127.0.0.1:<port>/"`. One honest caveat, worth half a sentence if it comes up — a
|
|
51
|
+
console that is already running is serving the project it was *launched* from, so if they want this
|
|
52
|
+
project's view they can stop that one (`^C` in its terminal) and run this again.
|
|
53
|
+
|
|
54
|
+
## 4. Hand it over and stop
|
|
55
|
+
|
|
56
|
+
Give them the URL as a clickable line, and one warm sentence: the page is **read-only until you
|
|
57
|
+
click**, every machine change is **explained first and reversible**, and Settings save at the user
|
|
58
|
+
level only. Worth naming once: the brain's on/off switch is the first card on the page, and the
|
|
59
|
+
header chip says how fresh the reading is and re-measures if they click it.
|
|
60
|
+
|
|
61
|
+
## 5. If it errors
|
|
62
|
+
|
|
63
|
+
Report it plainly — the real error, not a guess — and offer to fix it. Never leave them staring at
|
|
64
|
+
a dead tab wondering whether it is still loading.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Things NOT to do before the page is open
|
|
69
|
+
|
|
70
|
+
Each of these has cost a real user real minutes of silence, and not one of them is needed to open a
|
|
71
|
+
local web page:
|
|
72
|
+
|
|
73
|
+
- **No knowledge search, no memory recall, no source grounding, no repo exploration.** A cold
|
|
74
|
+
embedding-model load alone is allowed up to 180 seconds.
|
|
75
|
+
- **No model selection or routing work.**
|
|
76
|
+
- **No reading this repo to "check" anything first.** Find the script, run it.
|
|
77
|
+
|
|
78
|
+
Do **not** narrate the machine yourself afterwards; the page is the mirror. Your job is to open it,
|
|
79
|
+
say one sentence, and get out of the way.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "RvCB — RuvNet Brain Console (same console as /rvbc, /brain-console, and /ruvnet-brain:configure — every spelling works). Opens the live console page: your whole RuvNet stack on one page. Read-only until you click."
|
|
3
|
+
updated: 2026-07-20
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`/rvbc`, `/rvcb`, `/brain-console`, and `/ruvnet-brain:configure` are equally valid names. Never
|
|
7
|
+
correct the user's spelling.
|
|
8
|
+
|
|
9
|
+
1. Say: "Opening it now; it scans live while you watch."
|
|
10
|
+
2. Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
11
|
+
A current-repository copy is allowed only for an explicit developer checkout.
|
|
12
|
+
3. Run `node <resolved-script> --serve --open` in the background.
|
|
13
|
+
4. Give the URL immediately. Never promise a duration; the page reports its own progress.
|
|
14
|
+
|
|
15
|
+
An already-running server is success. It is read-only until the user clicks; changes must be
|
|
16
|
+
explained and reversible. If the script or server is unavailable, report the exact failure.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "What's new in RuvNet Brain — the big things in the current MAJOR release (4.0), in plain English. Not the point-release churn — the headline changes since 3.x. Ends by offering to open the Console so you can see it live."
|
|
3
|
+
updated: 2026-07-25
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RuvNet-Brain: what's new
|
|
7
|
+
|
|
8
|
+
The user wants the headline story of the **major** release they're on — the 4.0-vs-3.0 kind of change,
|
|
9
|
+
**not** the "3.9.x → 3.9.y" point-release churn. Deliver it warmly and honestly, then offer the Console.
|
|
10
|
+
|
|
11
|
+
**First, ground — never recite this from memory (it drifts every release):**
|
|
12
|
+
1. Read the running version from `${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json`. State it honestly.
|
|
13
|
+
**Do NOT claim "you're on 4.0"** unless the version literally starts with `4.` — per ADR-042 the
|
|
14
|
+
number stays `3.9.x-dev` until the 4.0 line is field-verified. The honest framing is: *"these are the
|
|
15
|
+
4.0-line enhancements, and you already have them — the version stamps to 4.0 once they're proven in
|
|
16
|
+
real use."*
|
|
17
|
+
2. Read `docs/RELEASE-NOTES-4.0.md` (the curated highlights + its VERSION STATUS banner). Its content is
|
|
18
|
+
the source of truth for what follows — summarize it, don't invent beside it, and carry its honest
|
|
19
|
+
version framing.
|
|
20
|
+
|
|
21
|
+
**Then tell them what the 4.0 line is — the honest headline (adapt to the notes file; do NOT overclaim):**
|
|
22
|
+
|
|
23
|
+
The 4.0 line is where the brain got **honest, legible, fast, and self-measuring** — landing now in the
|
|
24
|
+
3.9.x releases. The big things:
|
|
25
|
+
|
|
26
|
+
- **The Console is the front door.** One live local page (type `/rvbc`) — your whole RuvNet stack on
|
|
27
|
+
one screen: what's installed, what the AI has actually learned from *your* projects (real memories +
|
|
28
|
+
distilled lessons, drill-down to the verbatim cards), which subscription pays for what, and one-click
|
|
29
|
+
**reversible** fixes for anything stale. New in 4.0: a plain-English explainer on every card, each
|
|
30
|
+
suggestion labelled with its blast radius (*just this project* vs *every project*), safe on/off
|
|
31
|
+
checkboxes that only appear where the undo is proven, and a terminal-first install.
|
|
32
|
+
- **It will not lie about your machine.** Every number is measured live; "we couldn't check" never
|
|
33
|
+
renders as "off"; one project's state can never leak into another's view.
|
|
34
|
+
- **Fast, and it tells you when it's ready.** The console and tips page paint in well under a second;
|
|
35
|
+
on a first scan it shows a countdown and then says *"it's live — take a look at your page,"* so you're
|
|
36
|
+
never staring at nothing.
|
|
37
|
+
- **It measures itself now.** The brain records when it offered help and whether you acted on it, so it
|
|
38
|
+
can *prove* it's improving rather than assert it. **Be honest that this has only just started
|
|
39
|
+
collecting** — the proof accrues as you use it; it is not a claim of "proven better" yet.
|
|
40
|
+
- **It learns across your projects.** A lesson proven in one project can be promoted to your global
|
|
41
|
+
brain and now survives an update (tested against the real updater, not argued).
|
|
42
|
+
- **Runs on your account, cheapest capable model.** The QE suite and routing use your Claude account,
|
|
43
|
+
not an API key, at the least-powerful model that does the job.
|
|
44
|
+
|
|
45
|
+
**Then offer the Console (the point of the whole thing):**
|
|
46
|
+
|
|
47
|
+
End by offering to open it: *"Want me to open the Console so you can see all of this live? Just say the
|
|
48
|
+
word — or type `/rvbc`."* If they say yes, follow `rvbc.md` in this same directory exactly (including the
|
|
49
|
+
warm heads-up about the ~20s scan).
|
|
50
|
+
|
|
51
|
+
**Honesty rules for this command (same as the product):**
|
|
52
|
+
- If `docs/RELEASE-NOTES-4.0.md` is missing, say the notes aren't written yet and summarize from what
|
|
53
|
+
you can verify — never fabricate a highlight.
|
|
54
|
+
- Never claim a metric ("40% better", "95/100") the release has not independently earned. The self-
|
|
55
|
+
measurement is new and still filling; say so plainly.
|
|
56
|
+
- This is the MAJOR story only. If the user wants the point-release detail, point them at the repo's
|
|
57
|
+
release notes / `git log`.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "RuvNet Brain lifecycle hooks for Codex. Every command enters through a generation-independent wrapper and adapts the shared Brain hook bodies to Codex contracts.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "startup|resume|clear|compact",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" session-start",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"UserPromptSubmit": [
|
|
17
|
+
{
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" ground-ruvnet",
|
|
22
|
+
"timeout": 10
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" unprompted-speech UserPromptSubmit",
|
|
27
|
+
"timeout": 10
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"PreToolUse": [
|
|
33
|
+
{
|
|
34
|
+
"matcher": "^(Bash|Edit|Write|exec_command|functions\\.exec_command|functions__exec_command|apply_patch)$",
|
|
35
|
+
"hooks": [
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" hijack-ruvnet",
|
|
39
|
+
"timeout": 5
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"matcher": "Agent|spawn_agent",
|
|
45
|
+
"hooks": [
|
|
46
|
+
{
|
|
47
|
+
"type": "command",
|
|
48
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" route-dispatch",
|
|
49
|
+
"timeout": 5
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"matcher": "^(Edit|Write|apply_patch)$",
|
|
55
|
+
"hooks": [
|
|
56
|
+
{
|
|
57
|
+
"type": "command",
|
|
58
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" ground-before-write",
|
|
59
|
+
"timeout": 5
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"type": "command",
|
|
63
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" protect-state",
|
|
64
|
+
"timeout": 5
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" unprompted-speech PreToolUse-write",
|
|
69
|
+
"timeout": 5
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"matcher": "^(Bash|exec_command|functions\\.exec_command|functions__exec_command)$",
|
|
75
|
+
"hooks": [
|
|
76
|
+
{
|
|
77
|
+
"type": "command",
|
|
78
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" verify-interface",
|
|
79
|
+
"timeout": 5
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"type": "command",
|
|
83
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" design-wall",
|
|
84
|
+
"timeout": 5
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "command",
|
|
88
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" unprompted-speech PreToolUse-bash",
|
|
89
|
+
"timeout": 5
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"PostToolUse": [
|
|
95
|
+
{
|
|
96
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
97
|
+
"hooks": [
|
|
98
|
+
{
|
|
99
|
+
"type": "command",
|
|
100
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" grounding-stamp",
|
|
101
|
+
"timeout": 5
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"matcher": "^(Bash|Edit|Write|exec_command|functions\\.exec_command|functions__exec_command|apply_patch)$",
|
|
107
|
+
"hooks": [
|
|
108
|
+
{
|
|
109
|
+
"type": "command",
|
|
110
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" learn-capture",
|
|
111
|
+
"timeout": 5
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"matcher": "^(Edit|Write|apply_patch)$",
|
|
117
|
+
"hooks": [
|
|
118
|
+
{
|
|
119
|
+
"type": "command",
|
|
120
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" md-stamp",
|
|
121
|
+
"timeout": 5
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"matcher": "^(Bash|exec_command|functions\\.exec_command|functions__exec_command)$",
|
|
127
|
+
"hooks": [
|
|
128
|
+
{
|
|
129
|
+
"type": "command",
|
|
130
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" signal-watch",
|
|
131
|
+
"timeout": 5
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
"SessionEnd": [
|
|
137
|
+
{
|
|
138
|
+
"matcher": "other",
|
|
139
|
+
"hooks": [
|
|
140
|
+
{
|
|
141
|
+
"type": "command",
|
|
142
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" learn-flush",
|
|
143
|
+
"timeout": 3
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"Stop": [
|
|
149
|
+
{
|
|
150
|
+
"hooks": [
|
|
151
|
+
{
|
|
152
|
+
"type": "command",
|
|
153
|
+
"command": "node \"$HOME/.cache/ruvnet-brain/codex-hook.mjs\" continuation-gate",
|
|
154
|
+
"timeout": 10
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_note": "OUT-OF-SHIM HOOK CONTRACTS (ADR-055 §6). The per-hook contract — event, matcher, layer, codeRoot, mode, offBehavior, failureBehavior, timeout, budgets, state, dependencies, reachesStrangers, owner — is carried NATIVELY by plugin/scripts/hook-shim.mjs's dispatch table for every shim-routed registration. Everything registered outside that table has nowhere to carry it, which is how the whole non-plugin two thirds of this machine's mesh ended up with no declared answer to 'what happens when the brain is off' (ADR-055 F14). This file is the other half: a checked-in contract for every registration this REPO owns but does not route through the shim. scripts/hook-registry.mjs reads both, and tests/unit/hook-registry-lint.test.mjs fails any repo-owned registration absent from both — so a new one cannot be added silently. SCOPE, deliberately: this file declares only registrations THIS repo owns (plugin/hooks/hooks.json and this project's .claude/settings.json). It does NOT declare contracts for the machine owner's ~/.claude/settings.json or for third-party plugins — those are not ours to specify, and inventing an offBehavior for someone else's hook would be exactly the fiction the lint exists to prevent. They stay visible as documented machine-local findings in the lint's expected-red block.",
|
|
3
|
+
"_version": 1,
|
|
4
|
+
"contracts": [
|
|
5
|
+
{
|
|
6
|
+
"id": "project:version-bump-gate",
|
|
7
|
+
"layer": "project",
|
|
8
|
+
"event": "PreToolUse",
|
|
9
|
+
"matcher": "Bash",
|
|
10
|
+
"commandIncludes": "version-bump-gate.sh",
|
|
11
|
+
"mode": "blocking",
|
|
12
|
+
"offBehavior": "run",
|
|
13
|
+
"offReason": "ADR-054's discriminator, applied literally: this is an HONESTY wall, not a retrieval feature. It refuses a commit that changes behaviour without bumping the version — the signal every user's updater reads. Nothing about that becomes acceptable because the owner switched the retrieval brain off, and the gate reads git state only: no corpus, no network, no brain.",
|
|
14
|
+
"failureBehavior": "fail-open — a crash or unparseable payload permits the command and records degraded health; malfunction is never a decision (ADR-055 §1.2)",
|
|
15
|
+
"timeoutSeconds": 5,
|
|
16
|
+
"warmP95BudgetMs": 50,
|
|
17
|
+
"coldBudgetMs": 500,
|
|
18
|
+
"stdoutCapBytes": 4096,
|
|
19
|
+
"stateRead": ["git HEAD", "plugin/.claude-plugin/plugin.json"],
|
|
20
|
+
"stateWritten": [],
|
|
21
|
+
"dependencies": ["bash", "git"],
|
|
22
|
+
"reachesStrangers": false,
|
|
23
|
+
"owner": "ruvnet-brain (this repo only — ADR-053; it enforces a rule that is true here and nowhere else)",
|
|
24
|
+
"note": "Project-scoped on purpose: it lived in the GLOBAL settings until 2026-07-14, taxing every Bash call in 34+ projects with a rule true in one."
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"matcherAllowlist": [
|
|
28
|
+
{
|
|
29
|
+
"layer": "plugin",
|
|
30
|
+
"event": "PreToolUse",
|
|
31
|
+
"matcher": "Write|Edit|Bash",
|
|
32
|
+
"handler": "hijack-ruvnet.sh",
|
|
33
|
+
"reason": "UNANCHORED, known (ADR-055 F4). Claude Code SEARCHES the tool name, so this also selects MultiEdit, NotebookEdit, TodoWrite and BashOutput — an advisory hook firing on four tools nobody chose. Advisory, so the blast radius is wasted latency rather than a wrong refusal.",
|
|
34
|
+
"retiredBy": "ADR-055 build item 3 (four plane dispatchers) — registration changes are SHELL changes and item 2 (battery v2) must land first, so this is recorded, not fixed out of order."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"layer": "plugin",
|
|
38
|
+
"event": "PreToolUse",
|
|
39
|
+
"matcher": "Bash",
|
|
40
|
+
"handler": "verify-interface.sh",
|
|
41
|
+
"reason": "UNANCHORED, known (ADR-055 F4/F12): also selects BashOutput. One of three blocking walls on the same event that each re-parse the same payload — the parse-once execution-guard is the real fix, not six anchor characters.",
|
|
42
|
+
"retiredBy": "ADR-055 build item 3 (execution-guard.mjs — ONE registration, ONE parse)"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"layer": "plugin",
|
|
46
|
+
"event": "PreToolUse",
|
|
47
|
+
"matcher": "Bash",
|
|
48
|
+
"handler": "design-wall.sh",
|
|
49
|
+
"reason": "UNANCHORED, known (ADR-055 F4/F12) — same pair as verify-interface above, same fix.",
|
|
50
|
+
"retiredBy": "ADR-055 build item 3 (execution-guard.mjs)"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"layer": "plugin",
|
|
54
|
+
"event": "PostToolUse",
|
|
55
|
+
"matcher": "Write|Edit|MultiEdit|Bash",
|
|
56
|
+
"handler": "learn-capture.sh",
|
|
57
|
+
"reason": "UNANCHORED, known (ADR-055 F4): NotebookEdit reaches the learning pipeline by substring accident, never by decision. Advisory.",
|
|
58
|
+
"retiredBy": "ADR-055 build item 3"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"layer": "plugin",
|
|
62
|
+
"event": "PostToolUse",
|
|
63
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
64
|
+
"handler": "md-stamp.mjs",
|
|
65
|
+
"reason": "UNANCHORED, known (ADR-055 F4): same NotebookEdit substring accident. Advisory.",
|
|
66
|
+
"retiredBy": "ADR-055 build item 3"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"layer": "project",
|
|
70
|
+
"event": "PreToolUse",
|
|
71
|
+
"matcher": "Bash",
|
|
72
|
+
"handler": "version-bump-gate.sh",
|
|
73
|
+
"reason": "UNANCHORED, known: also selects BashOutput, which carries no command to gate, so the gate reads an empty payload and permits. Wasted spawn, not a wrong refusal.",
|
|
74
|
+
"retiredBy": "ADR-055 build item 3, together with the plugin-layer Bash walls it sits beside"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "POSIX Stable Spine (ADR-023): every hook routes through hook-shim.mjs, which resolves the active generation per invocation. Advisory hooks fail open; blocking hooks preserve their exit-code contract.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "startup",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" session-start || true",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"matcher": "resume",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" session-start || true",
|
|
21
|
+
"timeout": 5
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"UserPromptSubmit": [
|
|
27
|
+
{
|
|
28
|
+
"matcher": ".*",
|
|
29
|
+
"hooks": [
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" ground-ruvnet || true",
|
|
33
|
+
"timeout": 10
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"matcher": "*",
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" unprompted-speech UserPromptSubmit",
|
|
43
|
+
"timeout": 10
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"PreToolUse": [
|
|
49
|
+
{
|
|
50
|
+
"matcher": "Write|Edit|Bash",
|
|
51
|
+
"hooks": [
|
|
52
|
+
{
|
|
53
|
+
"type": "command",
|
|
54
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" hijack-ruvnet || true",
|
|
55
|
+
"timeout": 5
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"matcher": "^(Task|Agent)$",
|
|
61
|
+
"hooks": [
|
|
62
|
+
{
|
|
63
|
+
"type": "command",
|
|
64
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" route-dispatch",
|
|
65
|
+
"timeout": 5
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit)$",
|
|
71
|
+
"hooks": [
|
|
72
|
+
{
|
|
73
|
+
"type": "command",
|
|
74
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" ground-before-write || true",
|
|
75
|
+
"timeout": 5
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "command",
|
|
79
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" protect-state",
|
|
80
|
+
"timeout": 5
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"matcher": "Bash",
|
|
86
|
+
"hooks": [
|
|
87
|
+
{
|
|
88
|
+
"type": "command",
|
|
89
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" verify-interface || true",
|
|
90
|
+
"timeout": 5
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"matcher": "Bash",
|
|
96
|
+
"hooks": [
|
|
97
|
+
{
|
|
98
|
+
"type": "command",
|
|
99
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" design-wall",
|
|
100
|
+
"timeout": 5
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"matcher": "^(Write|Edit|MultiEdit)$",
|
|
106
|
+
"hooks": [
|
|
107
|
+
{
|
|
108
|
+
"type": "command",
|
|
109
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" unprompted-speech PreToolUse-write",
|
|
110
|
+
"timeout": 5
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"matcher": "^Bash$",
|
|
116
|
+
"hooks": [
|
|
117
|
+
{
|
|
118
|
+
"type": "command",
|
|
119
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" unprompted-speech PreToolUse-bash",
|
|
120
|
+
"timeout": 5
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"PostToolUse": [
|
|
126
|
+
{
|
|
127
|
+
"matcher": "^(Task|Agent)$",
|
|
128
|
+
"hooks": [
|
|
129
|
+
{
|
|
130
|
+
"type": "command",
|
|
131
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" routing-outcome || true",
|
|
132
|
+
"timeout": 5
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
138
|
+
"hooks": [
|
|
139
|
+
{
|
|
140
|
+
"type": "command",
|
|
141
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" grounding-stamp || true",
|
|
142
|
+
"timeout": 5
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"matcher": "Write|Edit|MultiEdit|Bash",
|
|
148
|
+
"hooks": [
|
|
149
|
+
{
|
|
150
|
+
"type": "command",
|
|
151
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" learn-capture || true",
|
|
152
|
+
"timeout": 5
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
158
|
+
"hooks": [
|
|
159
|
+
{
|
|
160
|
+
"type": "command",
|
|
161
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" md-stamp || true",
|
|
162
|
+
"timeout": 5
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"matcher": "^Bash$",
|
|
168
|
+
"hooks": [
|
|
169
|
+
{
|
|
170
|
+
"type": "command",
|
|
171
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" signal-watch || true",
|
|
172
|
+
"timeout": 5
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"SessionEnd": [
|
|
178
|
+
{
|
|
179
|
+
"matcher": ".*",
|
|
180
|
+
"hooks": [
|
|
181
|
+
{
|
|
182
|
+
"type": "command",
|
|
183
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" learn-flush || true",
|
|
184
|
+
"timeout": 30
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
"Stop": [
|
|
190
|
+
{
|
|
191
|
+
"matcher": "*",
|
|
192
|
+
"hooks": [
|
|
193
|
+
{
|
|
194
|
+
"type": "command",
|
|
195
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" continuation-gate || true",
|
|
196
|
+
"timeout": 10
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { loadRuntimePreferences, runtimeChildEnv } from '../scripts/runtime-preferences.mjs';
|
|
5
6
|
|
|
6
7
|
export const MANAGED_EXECUTABLES = Object.freeze([
|
|
7
8
|
'ruflo',
|
|
@@ -142,9 +143,21 @@ function writeStamps(executable, argv, env) {
|
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
export function resolveManagedExecutable(executable, env = process.env) {
|
|
147
|
+
if (executable !== 'ruflo') return executable;
|
|
148
|
+
const home = env.HOME || os.homedir();
|
|
149
|
+
const canonical = path.join(home, '.npm-global', 'bin', 'ruflo');
|
|
150
|
+
try {
|
|
151
|
+
fs.accessSync(canonical, fs.constants.X_OK);
|
|
152
|
+
return canonical;
|
|
153
|
+
} catch {
|
|
154
|
+
return executable;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
145
158
|
function execute(executable, argv, env) {
|
|
146
159
|
return new Promise((resolve) => {
|
|
147
|
-
const child = spawn(executable, argv, {
|
|
160
|
+
const child = spawn(resolveManagedExecutable(executable, env), argv, {
|
|
148
161
|
env,
|
|
149
162
|
shell: false,
|
|
150
163
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -186,8 +199,9 @@ function execute(executable, argv, env) {
|
|
|
186
199
|
|
|
187
200
|
function resultOf(executable, argv, result) {
|
|
188
201
|
const output = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? '\n' : '');
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
const contradictoryFailure = /(?:^|\n)\s*(?:❌|\[ERROR\])|invalid pragma command|key not found/i.test(output);
|
|
203
|
+
if (result.error || result.code !== 0 || contradictoryFailure) {
|
|
204
|
+
const reason = result.error || (contradictoryFailure ? 'fatal output despite exit 0' : `exit ${result.code}`);
|
|
191
205
|
return {
|
|
192
206
|
content: [{ type: 'text', text: output || `${executable} ${argv.join(' ')} failed: ${reason}` }],
|
|
193
207
|
isError: true,
|
|
@@ -220,7 +234,36 @@ export async function callManagedCli(toolName, args, env = process.env) {
|
|
|
220
234
|
isError: true,
|
|
221
235
|
};
|
|
222
236
|
}
|
|
223
|
-
|
|
237
|
+
const policy = loadRuntimePreferences({ env, cwd: env.RUVNET_BRAIN_PROJECT_DIR || process.cwd() });
|
|
238
|
+
if (executable === 'agentic-flow' && policy.values.routing !== 'auto') {
|
|
239
|
+
return {
|
|
240
|
+
content: [{
|
|
241
|
+
type: 'text',
|
|
242
|
+
text: policy.values.routing === 'off'
|
|
243
|
+
? 'Token-smart routing is off in RuvNet Brain Console; agentic-flow was not started.'
|
|
244
|
+
: 'Token-smart routing has not been enabled in RuvNet Brain Console; agentic-flow was not started.',
|
|
245
|
+
}],
|
|
246
|
+
isError: true,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const isFleetMutation = executable === 'agentic-qe'
|
|
250
|
+
&& argv[0] === 'fleet'
|
|
251
|
+
&& ['init', 'spawn', 'run'].includes(argv[1]);
|
|
252
|
+
if (isFleetMutation && policy.values.qeFleet !== true) {
|
|
253
|
+
return {
|
|
254
|
+
content: [{
|
|
255
|
+
type: 'text',
|
|
256
|
+
text: policy.values.qeFleet === false
|
|
257
|
+
? 'The Agentic-QE fleet is off in RuvNet Brain Console; no QE agents were started.'
|
|
258
|
+
: 'The Agentic-QE fleet has not been enabled in RuvNet Brain Console; no QE agents were started.',
|
|
259
|
+
}],
|
|
260
|
+
isError: true,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const childEnv = (executable === 'agentic-flow' || executable === 'agentic-qe')
|
|
264
|
+
? runtimeChildEnv({ env, cwd: env.RUVNET_BRAIN_PROJECT_DIR || process.cwd() })
|
|
265
|
+
: env;
|
|
266
|
+
return resultOf(executable, argv, await execute(executable, argv, childEnv));
|
|
224
267
|
}
|
|
225
268
|
|
|
226
269
|
return {
|