ruvnet-brain 4.7.19 → 4.7.21
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/README.md +2 -2
- package/bin/install.mjs +494 -97
- package/kb/download-retry.mjs +93 -21
- package/kb/forge-guard-injection.mjs +277 -0
- package/kb/forge-update.mjs +166 -38
- package/kb/lifecycle-evidence-retention.mjs +151 -14
- package/kb/model-requirements.mjs +4 -1
- package/kb/refresh-run.mjs +175 -27
- package/kb/verify-citation.mjs +15 -2
- package/package.json +3 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/mcp/managed-cli-interface.mjs +16 -8
- package/plugin/scripts/adr-currency-gate.mjs +2 -1
- package/plugin/scripts/advisory-contract.mjs +21 -0
- package/plugin/scripts/advocacy-route.mjs +5 -4
- package/plugin/scripts/agentdb-recall.mjs +15 -5
- package/plugin/scripts/automatic-update.mjs +9 -1
- package/plugin/scripts/brain-confirmation.mjs +2 -1
- package/plugin/scripts/brain-footprint.mjs +72 -11
- package/plugin/scripts/capability-registry.mjs +1 -1
- package/plugin/scripts/capacity-aware-parallel-work.mjs +2 -1
- package/plugin/scripts/codex-overnight-notice.mjs +33 -0
- package/plugin/scripts/completion-claim-evidence.mjs +56 -12
- package/plugin/scripts/continuation-gate.mjs +28 -9
- package/plugin/scripts/decision-gate.mjs +13 -63
- package/plugin/scripts/decision-outcomes.mjs +36 -0
- package/plugin/scripts/decision-recall-gate.mjs +40 -5
- package/plugin/scripts/decision-record.mjs +8 -3
- package/plugin/scripts/degradation-watch.mjs +2 -1
- package/plugin/scripts/developer-update-lock.mjs +172 -33
- package/plugin/scripts/developer-update-owner.mjs +8 -5
- package/plugin/scripts/developer-update-policy.mjs +4 -1
- package/plugin/scripts/developer-update.mjs +155 -53
- package/plugin/scripts/doc-currency.mjs +2 -16
- package/plugin/scripts/duplicate-gate.mjs +2 -1
- package/plugin/scripts/entrypoint.mjs +34 -0
- package/plugin/scripts/footprint-io.mjs +135 -8
- package/plugin/scripts/grok-hook-adapter.mjs +2 -1
- package/plugin/scripts/ground-ruvnet.sh +6 -3
- package/plugin/scripts/grounding-answer.mjs +2 -1
- package/plugin/scripts/grounding-code-projection.mjs +2 -1
- package/plugin/scripts/grounding-substance.mjs +2 -1
- package/plugin/scripts/grounding-turn-gate.mjs +2 -2
- package/plugin/scripts/grounding-turn-mark.mjs +2 -2
- package/plugin/scripts/hook-context-budget.mjs +2 -1
- package/plugin/scripts/hook-input.mjs +2 -2
- package/plugin/scripts/hook-shim.mjs +9 -2
- package/plugin/scripts/host-update.mjs +29 -5
- package/plugin/scripts/identifier-preflight.mjs +2 -1
- package/plugin/scripts/kb-copy-proof.mjs +57 -9
- package/plugin/scripts/learn-capture.mjs +2 -1
- package/plugin/scripts/learning-store.mjs +62 -16
- package/plugin/scripts/lesson-bridge.mjs +2 -2
- package/plugin/scripts/lesson-promote.mjs +83 -22
- package/plugin/scripts/md-stamp.mjs +2 -1
- package/plugin/scripts/native-turn-transcript.mjs +98 -6
- package/plugin/scripts/nightly-scheduler.mjs +10 -5
- package/plugin/scripts/package-recommender.mjs +2 -2
- package/plugin/scripts/project-store-resolver.mjs +19 -0
- package/plugin/scripts/routing-outcome-capture.mjs +2 -1
- package/plugin/scripts/session-snapshot-hook.mjs +24 -4
- package/plugin/scripts/session-start-core.mjs +8 -16
- package/plugin/scripts/session-start-health.mjs +97 -10
- package/plugin/scripts/session-start-issue-alert.mjs +105 -0
- package/plugin/scripts/session-start-update-plane.mjs +15 -1
- package/plugin/scripts/signal-watch.mjs +2 -1
- package/plugin/scripts/spend-guard.mjs +2 -1
- package/plugin/scripts/substitution-wall.mjs +2 -1
- package/plugin/scripts/turn-outcome-capture.mjs +7 -3
- package/plugin/scripts/unprompted-runtime.mjs +20 -3
- package/plugin/scripts/update-apply.mjs +186 -15
- package/plugin/skills/release-proof/scripts/release-proof.mjs +2 -1
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +2 -2
- package/plugin/skills/ruvnet-brain/SKILL.md +3 -2
- package/scripts/adr-072-completion.mjs +2 -1
- package/scripts/agentdb-context.mjs +2 -1
- package/scripts/agentdb-fleet-doctor.mjs +30 -8
- package/scripts/approved-runtime.mjs +2 -1
- package/scripts/architecture-review-lock.mjs +2 -1
- package/scripts/ascii-drift.mjs +2 -1
- package/scripts/brain-latency-50.mjs +2 -1
- package/scripts/brain-novice-50.mjs +2 -16
- package/scripts/brain-score.mjs +13 -2
- package/scripts/build-bundle.mjs +2 -1
- package/scripts/build-concepts.mjs +2 -1
- package/scripts/candidate-ci-receipt.mjs +2 -1
- package/scripts/candidate-host-evidence.mjs +2 -1
- package/scripts/card-from-source.mjs +2 -1
- package/scripts/ci/warm-brain-models.mjs +2 -1
- package/scripts/claims-verify.mjs +7 -3
- package/scripts/claude-controlled-terminal.mjs +2 -1
- package/scripts/claude-terminal-mod.mjs +2 -1
- package/scripts/code-release-corpus.mjs +2 -1
- package/scripts/codex-hook-trust-reconcile.mjs +67 -1
- package/scripts/codex-hook-trust.mjs +40 -1
- package/scripts/codex-hook-wrapper-history.mjs +2 -1
- package/scripts/codex-host-execution-proof.mjs +2 -1
- package/scripts/completion-claim-replay.mjs +2 -1
- package/scripts/console-engine.mjs +8 -3
- package/scripts/corpus-canary.mjs +2 -1
- package/scripts/corpus-candidate.mjs +2 -2
- package/scripts/corpus-coverage-sidecar.mjs +2 -1
- package/scripts/corpus-dispatch-decision.mjs +2 -1
- package/scripts/corpus-dispatch-receipt.mjs +2 -1
- package/scripts/corpus-next-seed.mjs +2 -1
- package/scripts/corpus-qa.mjs +2 -1
- package/scripts/corpus-reconcile.mjs +2 -2
- package/scripts/corpus-watchdog.mjs +2 -1
- package/scripts/count-chunks.mjs +2 -1
- package/scripts/customer-state-matrix.mjs +2 -1
- package/scripts/derive-passage-content-map.mjs +2 -1
- package/scripts/development-push-check.mjs +2 -1
- package/scripts/dispatch-receipt.mjs +2 -1
- package/scripts/doc-currency.mjs +2 -1
- package/scripts/dream-issue-gate.mjs +2 -1
- package/scripts/dual-host-deliberation.mjs +2 -16
- package/scripts/dual-host-suggest.mjs +2 -16
- package/scripts/eval-brain.mjs +7 -3
- package/scripts/execution-policy.mjs +2 -1
- package/scripts/execution-preflight.mjs +2 -1
- package/scripts/falsify.mjs +2 -1
- package/scripts/fix-metaharness-memretrieve.mjs +2 -1
- package/scripts/fix-workstream.mjs +2 -1
- package/scripts/full-hints.mjs +2 -1
- package/scripts/full-suite-gate.mjs +2 -1
- package/scripts/grok-host.mjs +68 -0
- package/scripts/hook-qualify-core.mjs +3 -1
- package/scripts/hook-qualify.mjs +2 -1
- package/scripts/hook-retirement-check.mjs +2 -1
- package/scripts/host-registry.mjs +2 -1
- package/scripts/independent-review-receipt.mjs +2 -1
- package/scripts/ingest-new-repos.mjs +2 -1
- package/scripts/ingest-repo.mjs +12 -2
- package/scripts/integration-evidence.mjs +2 -1
- package/scripts/issue-fix.mjs +7 -24
- package/scripts/issue-watch.mjs +164 -47
- package/scripts/job-heartbeat.sh +145 -13
- package/scripts/key-canary.mjs +9 -3
- package/scripts/latency-to-surface.mjs +2 -1
- package/scripts/learning-replay-cli.mjs +97 -19
- package/scripts/learning-replay-execution.mjs +2 -0
- package/scripts/learning-replay-fixture.mjs +3 -0
- package/scripts/learning-replay-proof.mjs +14 -13
- package/scripts/learning-replay.mjs +3 -3
- package/scripts/learnings.mjs +2 -1
- package/scripts/lesson-ratify.mjs +88 -40
- package/scripts/loop-checkpoint.mjs +2 -1
- package/scripts/metaharness-receipts.mjs +2 -1
- package/scripts/model-catalog.mjs +2 -1
- package/scripts/model-currency-evidence.mjs +6 -4
- package/scripts/model-currency.mjs +33 -3
- package/scripts/model-native-catalog.mjs +2 -1
- package/scripts/model-router-agent-hook.mjs +2 -1
- package/scripts/model-router-dispatch.mjs +2 -1
- package/scripts/model-router-engine.mjs +2 -1
- package/scripts/model-router-outcome.mjs +2 -1
- package/scripts/model-router-setup.mjs +2 -1
- package/scripts/model-routing-eval.mjs +2 -1
- package/scripts/model-routing-gateway.mjs +2 -1
- package/scripts/model-routing-launchers.mjs +4 -1
- package/scripts/model-terminal-gateway.mjs +2 -1
- package/scripts/model-terminal-launchers.mjs +2 -1
- package/scripts/model-weekly-analyst.mjs +2 -1
- package/scripts/model-weekly-cycle.mjs +2 -1
- package/scripts/model-weekly-qualification.mjs +2 -1
- package/scripts/nightly-gists.sh +30 -21
- package/scripts/nightly-two-run-proof.mjs +2 -1
- package/scripts/nightly-watchdog.mjs +158 -47
- package/scripts/no-silent-substitution.mjs +2 -1
- package/scripts/notify.sh +11 -6
- package/scripts/ntfy-inbox.mjs +549 -0
- package/scripts/onboarding-console.mjs +47 -8
- package/scripts/oracle/abstain-threshold-sweep.mjs +2 -1
- package/scripts/oracle/abstain-trace.mjs +2 -1
- package/scripts/oracle/doc2query-generate.mjs +2 -1
- package/scripts/oracle/doc2query-reach.mjs +2 -1
- package/scripts/oracle/judge-train.mjs +2 -1
- package/scripts/oracle/need-set-split.mjs +2 -1
- package/scripts/oracle/produce-questions.mjs +2 -16
- package/scripts/oracle/repo-recall.mjs +2 -2
- package/scripts/oracle/retrieval-accuracy.mjs +2 -2
- package/scripts/oracle/sona-query-adapter-eval.mjs +2 -1
- package/scripts/oracle/source-tree.mjs +2 -15
- package/scripts/oracle/source-units.mjs +2 -16
- package/scripts/oracle/spike-run.mjs +2 -16
- package/scripts/oracle/validate-labels.mjs +2 -16
- package/scripts/org-repo-count.mjs +2 -1
- package/scripts/package-cards.mjs +2 -1
- package/scripts/prepublication-evidence.mjs +2 -1
- package/scripts/private-overlay.mjs +2 -1
- package/scripts/product-integrity-contract.mjs +2 -1
- package/scripts/protected-release-invocation.mjs +2 -1
- package/scripts/public-verification-abandon.mjs +2 -1
- package/scripts/public-verification-aggregate.mjs +2 -1
- package/scripts/public-verification-finalizer.mjs +2 -1
- package/scripts/public-verification-inputs.mjs +2 -1
- package/scripts/public-verification-lane.mjs +2 -1
- package/scripts/publication-receipt.mjs +2 -1
- package/scripts/published-surface-probe.mjs +2 -1
- package/scripts/qe/card-lane-gate.mjs +2 -16
- package/scripts/qe/session-start-gate.mjs +2 -16
- package/scripts/qe/ux-suite.mjs +2 -1
- package/scripts/qualified-candidate-check.mjs +2 -1
- package/scripts/rebuild-gists-from-receipts.mjs +2 -1
- package/scripts/recommendation-eval.mjs +2 -1
- package/scripts/recommendation-floor.mjs +2 -1
- package/scripts/recommendation-judge-score.mjs +2 -1
- package/scripts/recommendation-real-host-score.mjs +2 -1
- package/scripts/recommendation-real-host.mjs +2 -1
- package/scripts/refresh-capability-only-store.mjs +2 -1
- package/scripts/refresh-model-catalog.mjs +2 -1
- package/scripts/rehearse-corpus-pipeline.mjs +2 -1
- package/scripts/release-authority.mjs +2 -1
- package/scripts/release-evidence-aggregate.mjs +2 -1
- package/scripts/release-payload.mjs +2 -1
- package/scripts/release-projection.mjs +2 -1
- package/scripts/release-proof.mjs +2 -1
- package/scripts/release-qualification-contract.mjs +71 -26
- package/scripts/release-qualification.mjs +8 -1
- package/scripts/release-vector.mjs +2 -1
- package/scripts/restore-local-ingests.mjs +2 -1
- package/scripts/retrieval-canary.mjs +2 -1
- package/scripts/route-cheap.mjs +2 -1
- package/scripts/route-gold-rank.mjs +2 -1
- package/scripts/route-index-memory.mjs +2 -1
- package/scripts/route-latency-warm.mjs +2 -1
- package/scripts/router-utilization.mjs +2 -1
- package/scripts/routing-flywheel.mjs +2 -1
- package/scripts/run-operational-benchmark.mjs +2 -1
- package/scripts/run-operational-benchmark.v3.mjs +2 -1
- package/scripts/rvf-index-audit.mjs +2 -16
- package/scripts/seal-gist-receipt.mjs +2 -1
- package/scripts/security-guidance-codex-compat.mjs +2 -1
- package/scripts/selfcheck.mjs +2 -1
- package/scripts/signal-watch.mjs +2 -1
- package/scripts/source-coverage.mjs +2 -1
- package/scripts/stabilization-receipt.mjs +2 -1
- package/scripts/stamp-sweep.mjs +2 -1
- package/scripts/status-honesty.mjs +2 -1
- package/scripts/sync-commands.mjs +2 -2
- package/scripts/top100-benchmark.mjs +2 -1
- package/scripts/top100-corpus.mjs +2 -1
- package/scripts/user-model-hook-install.mjs +2 -1
- package/scripts/user-model-prompt-hook.mjs +2 -1
- package/scripts/verify-bundle.mjs +3 -1
- package/scripts/verify-model-catalog.mjs +2 -1
- package/scripts/version.mjs +2 -1
- package/scripts/wired-check.mjs +11 -5
- package/scripts/worktree-integrity.mjs +2 -2
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import { hardProblem } from './dual-host-deliberation.mjs';
|
|
6
6
|
import { probeSubscriptionHosts } from './subscription-hosts.mjs';
|
|
7
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
7
8
|
|
|
8
9
|
const HOSTS = Object.freeze([
|
|
9
10
|
['claude', 'claude-code'],
|
|
@@ -54,21 +55,6 @@ export function main(argv = process.argv.slice(2), {
|
|
|
54
55
|
return 0;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
// NOT follow symlinks, while import.meta.url IS symlink-resolved by Node. Through a symlink (npm bin
|
|
59
|
-
// shims, wrapper scripts, and every os.tmpdir() path on macOS) the two sides disagree, so main()
|
|
60
|
-
// never runs -- and because nothing throws, the process exits 0. A silent exit 0 is indistinguishable
|
|
61
|
-
// from "ran, found nothing", which is how prepareCorpusCandidate once reported SUCCESS with no
|
|
62
|
-
// archive on disk. Reproduced live 2026-07-27; pinned by tests/unit/entrypoint-symlink.test.mjs.
|
|
63
|
-
function isDirectInvocation() {
|
|
64
|
-
try {
|
|
65
|
-
if (!process.argv[1]) return false;
|
|
66
|
-
return fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url));
|
|
67
|
-
} catch {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (isDirectInvocation()) {
|
|
58
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
73
59
|
process.exitCode = main();
|
|
74
60
|
}
|
package/scripts/eval-brain.mjs
CHANGED
|
@@ -32,6 +32,7 @@ import os from 'node:os';
|
|
|
32
32
|
import path from 'node:path';
|
|
33
33
|
import { spawnSync } from 'node:child_process';
|
|
34
34
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
35
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
35
36
|
|
|
36
37
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
37
38
|
const KB = process.env.RUVNET_BRAIN_KB || path.join(os.homedir(), '.cache', 'ruvnet-brain', 'kb');
|
|
@@ -91,8 +92,11 @@ export function gradeQuestion(q, { grounded, citations, bannerPresent, receipt,
|
|
|
91
92
|
return { grounded, routed: null, abstained, pass: abstained };
|
|
92
93
|
case 'provenance':
|
|
93
94
|
// The mechanism under test: IF a gist chunk wins, it must carry its own status banner.
|
|
94
|
-
// A better hit from the real repo is not a failure — it is better grounding.
|
|
95
|
-
|
|
95
|
+
// A better hit from the real repo is not a failure — it is better grounding. "Wins" means
|
|
96
|
+
// the citation verify-citation.mjs actually resolved (`routedRepo`, the same signal `routed`
|
|
97
|
+
// uses below) — not merely the raw top-ranked citation, which citationResolves() can walk
|
|
98
|
+
// past when it is unverified/fabricated (the sibling gap already closed for `routed`).
|
|
99
|
+
return { grounded, routed: null, abstained, pass: !!grounded && !abstained && (routedRepo !== 'ruv-gists' || bannerPresent) };
|
|
96
100
|
default:
|
|
97
101
|
// Abstention is correct only for the adversarial stratum. A negative cross-encoder score on
|
|
98
102
|
// an answerable question is an answer miss, even when an unrelated existing path resolves.
|
|
@@ -279,6 +283,6 @@ async function main() {
|
|
|
279
283
|
}
|
|
280
284
|
}
|
|
281
285
|
|
|
282
|
-
if (
|
|
286
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
283
287
|
await main();
|
|
284
288
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// One deterministic boundary between Brain knowledge and consequential execution.
|
|
3
3
|
// This module is deliberately pure: it never loads credentials, calls a provider, or mutates state.
|
|
4
4
|
|
|
5
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
5
6
|
const NATIVE_HOSTS = new Set(['claude', 'codex']);
|
|
6
7
|
const API_EXECUTORS = new Set(['agent_execute', 'sdk', 'openrouter', 'api']);
|
|
7
8
|
const ACTIONS = new Set(['read', 'write', 'delegate', 'release', 'external']);
|
|
@@ -111,7 +112,7 @@ export function classifyExecutionPolicy(input = {}) {
|
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
if (import.meta.url
|
|
115
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
115
116
|
const raw = process.argv[2] || '{}';
|
|
116
117
|
let input;
|
|
117
118
|
try { input = JSON.parse(raw); } catch { process.stderr.write('execution-policy: input must be JSON\n'); process.exit(2); }
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
// live Brain search and exact project AgentDB retrieval; prose, memory, and guessed host state do
|
|
4
4
|
// not satisfy this command.
|
|
5
5
|
import { classifyExecutionPolicy } from './execution-policy.mjs';
|
|
6
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
6
7
|
|
|
7
8
|
export function runExecutionPreflight(input = {}) {
|
|
8
9
|
return classifyExecutionPolicy({ ...input, enforceEvidence: true });
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
if (import.meta.url
|
|
12
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
12
13
|
let input;
|
|
13
14
|
try { input = JSON.parse(process.argv[2] || '{}'); }
|
|
14
15
|
catch { process.stderr.write('execution-preflight: input must be JSON\n'); process.exit(2); }
|
package/scripts/falsify.mjs
CHANGED
|
@@ -29,6 +29,7 @@ import fs from 'node:fs';
|
|
|
29
29
|
import path from 'node:path';
|
|
30
30
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
31
31
|
import { resolveRuflo, RUFLO_MISSING } from '../plugin/scripts/ruflo-bin.mjs';
|
|
32
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
32
33
|
|
|
33
34
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
34
35
|
const sh = (cmd, args) => spawnSync(cmd, args, { cwd: ROOT, encoding: 'utf8' });
|
|
@@ -238,4 +239,4 @@ function main() {
|
|
|
238
239
|
process.exit(0);
|
|
239
240
|
}
|
|
240
241
|
|
|
241
|
-
if (
|
|
242
|
+
if (isDirectInvocation(import.meta.url)) main();
|
|
@@ -28,6 +28,7 @@ import fs from 'node:fs';
|
|
|
28
28
|
import path from 'node:path';
|
|
29
29
|
import os from 'node:os';
|
|
30
30
|
import { pathToFileURL } from 'node:url';
|
|
31
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
31
32
|
|
|
32
33
|
const TARGET_DIR =
|
|
33
34
|
process.env.METAHARNESS_SCRIPTS_DIR ||
|
|
@@ -113,7 +114,7 @@ export function check(dir = TARGET_DIR, log = console.log) {
|
|
|
113
114
|
// Only act when run directly, so tests can import the pure functions above.
|
|
114
115
|
// Compare in URL space (pathToFileURL), not by decoding a URL into a path: `new URL(...).pathname`
|
|
115
116
|
// yields "/D:/..." on Windows and never matches, so `--apply` would silently no-op there.
|
|
116
|
-
const invokedDirectly =
|
|
117
|
+
const invokedDirectly = isDirectInvocation(import.meta.url);
|
|
117
118
|
if (invokedDirectly) {
|
|
118
119
|
const mode = process.argv.includes('--check') ? 'check' : 'apply';
|
|
119
120
|
console.log(`metaharness memRetrieve ${mode} — ${TARGET_DIR}\n`);
|
|
@@ -7,6 +7,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { pathToFileURL } from 'node:url';
|
|
10
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
10
11
|
|
|
11
12
|
const FULL_SHA = /^[a-f0-9]{40}$/i;
|
|
12
13
|
const SCOPED_BRANCH = /^(fix|bugfix|hotfix|issue|codex)\/[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
@@ -288,4 +289,4 @@ export function main(args = process.argv.slice(2)) {
|
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
|
|
291
|
-
if (
|
|
292
|
+
if (isDirectInvocation(import.meta.url)) process.exitCode = main();
|
package/scripts/full-hints.mjs
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// v2/crates — without --keep v2 those repos index almost nothing (open-claude-code: 68 passages
|
|
17
17
|
// total) and their FULL_HINTS can never match.
|
|
18
18
|
|
|
19
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
19
20
|
export const FULL_HINTS = {
|
|
20
21
|
'ruflo': 'v3/@claude-flow,v3/mcp,ruflo/src',
|
|
21
22
|
'synthlang': 'proxy/src/cli/synthlang,proxy/src/app/synthlang',
|
|
@@ -81,7 +82,7 @@ export const KEEP_DIRS = {
|
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
// CLI helper so shell drivers can read the config: node scripts/full-hints.mjs <kb-name>
|
|
84
|
-
if (import.meta.url
|
|
85
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
85
86
|
const kb = (process.argv[2] || '').toLowerCase();
|
|
86
87
|
console.log(JSON.stringify({ full: FULL_HINTS[kb] || null, keep: KEEP_DIRS[kb] || null }));
|
|
87
88
|
}
|
|
@@ -17,6 +17,7 @@ import os from 'node:os';
|
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { spawnSync } from 'node:child_process';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
20
21
|
|
|
21
22
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
22
23
|
const key = (file, name) => `${file} :: ${name}`;
|
|
@@ -132,7 +133,7 @@ export function summaryMarkdown(result) {
|
|
|
132
133
|
].join('\n');
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
if (
|
|
136
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
136
137
|
const args = process.argv.slice(2);
|
|
137
138
|
const value = (flag) => { const i = args.indexOf(flag); return i < 0 ? null : args[i + 1]; };
|
|
138
139
|
const out = value('--report') || path.join(os.tmpdir(), `full-suite-${process.pid}.json`);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grok CLI status for the installer summary and `--doctor` (#301).
|
|
3
|
+
*
|
|
4
|
+
* Grok has no install step of its own: it discovers the Claude Code plugin (measured with
|
|
5
|
+
* `grok inspect --json` on grok 1.0.58: plugin ruvnet-brain, 10 skills, its MCP server, and the
|
|
6
|
+
* hook file plugin/hooks/grok-hooks.json selected by plugin/.grok-plugin/plugin.json). Grok
|
|
7
|
+
* discards an allowing UserPromptSubmit hook's context (~/.grok/docs/user-guide/10-hooks.md), so the
|
|
8
|
+
* prompt-time "search first" directive never reaches its model; a line in ~/.grok/AGENTS.md (loaded
|
|
9
|
+
* as a global rule — same inspect run) is what makes Grok ground itself. That line is OPT-IN only.
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
|
|
15
|
+
export const GROK_MD_START = '<!-- ruvnet-brain:start -->';
|
|
16
|
+
export const GROK_MD_END = '<!-- ruvnet-brain:end -->';
|
|
17
|
+
export const GROK_AGENTS_LINE = 'For anything about the RuvNet / rUv stack (Ruflo, RuVector/RVF, AgentDB, agentic-flow, and the rest), '
|
|
18
|
+
+ 'call the `search_ruvnet` MCP tool first and cite the source paths it returns. Do not answer from memory. '
|
|
19
|
+
+ 'If it fails, say so and run `npx ruvnet-brain --doctor`.';
|
|
20
|
+
export const GROK_AGENTS_BLOCK = `${GROK_MD_START}\n${GROK_AGENTS_LINE}\n${GROK_MD_END}`;
|
|
21
|
+
|
|
22
|
+
export function grokPaths(home = os.homedir()) {
|
|
23
|
+
const bin = path.join(home, '.grok', 'bin');
|
|
24
|
+
return { bin: [path.join(bin, 'grok'), path.join(bin, 'grok.exe')], agents: path.join(home, '.grok', 'AGENTS.md') };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** What is true about Grok on this machine. Never runs grok; reads files only. */
|
|
28
|
+
export function grokStatus({ home = os.homedir(), pluginInstalled = false, hookCount = null } = {}) {
|
|
29
|
+
const p = grokPaths(home);
|
|
30
|
+
const present = p.bin.some((file) => fs.existsSync(file));
|
|
31
|
+
let agentsText = '';
|
|
32
|
+
try { agentsText = fs.readFileSync(p.agents, 'utf8'); } catch { /* absent */ }
|
|
33
|
+
return { present, pluginInstalled: Boolean(pluginInstalled), hookCount, agentsFile: p.agents,
|
|
34
|
+
groundingLine: /search_ruvnet/.test(agentsText) };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** One honest line: what reaches Grok, and whether the grounding line is there. null when no Grok. */
|
|
38
|
+
export function grokStatusLine(s) {
|
|
39
|
+
if (!s.present) return null;
|
|
40
|
+
if (!s.pluginInstalled) {
|
|
41
|
+
return 'Grok CLI detected — the Brain reaches Grok only through the Claude Code plugin, which is not installed here (run npx ruvnet-brain).';
|
|
42
|
+
}
|
|
43
|
+
const hooks = Number.isInteger(s.hookCount) ? `${s.hookCount} lifecycle hooks` : 'its lifecycle hooks';
|
|
44
|
+
return `Grok CLI detected — search_ruvnet, the Brain skills and ${hooks} (grok-hooks.json) load from the Claude Code plugin. `
|
|
45
|
+
+ 'Grok drops prompt-time context, so grounding relies on a search-first line in ~/.grok/AGENTS.md: '
|
|
46
|
+
+ (s.groundingLine ? 'present.' : 'absent (opt in: npx ruvnet-brain --grok-agents-md).');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Add the search-first line to ~/.grok/AGENTS.md ONLY if no search_ruvnet line is there already.
|
|
51
|
+
* Marker-wrapped (removed by --uninstall), backed up, written atomically. Returns
|
|
52
|
+
* 'added' | 'present' | 'no-grok' | 'failed'.
|
|
53
|
+
*/
|
|
54
|
+
export function addGrokAgentsLine({ home = os.homedir(), now = new Date() } = {}) {
|
|
55
|
+
const s = grokStatus({ home });
|
|
56
|
+
if (!s.present) return 'no-grok';
|
|
57
|
+
if (s.groundingLine) return 'present';
|
|
58
|
+
const file = s.agentsFile;
|
|
59
|
+
try {
|
|
60
|
+
const existing = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
61
|
+
if (existing) fs.copyFileSync(file, `${file}.bak-${now.toISOString().replace(/[:.]/g, '-')}`);
|
|
62
|
+
const next = existing ? `${existing.replace(/\s*$/, '')}\n\n${GROK_AGENTS_BLOCK}\n` : `${GROK_AGENTS_BLOCK}\n`;
|
|
63
|
+
const tmp = `${file}.ruvnet-tmp`;
|
|
64
|
+
fs.writeFileSync(tmp, next);
|
|
65
|
+
fs.renameSync(tmp, file);
|
|
66
|
+
return 'added';
|
|
67
|
+
} catch { return 'failed'; }
|
|
68
|
+
}
|
|
@@ -127,7 +127,9 @@ export function makeWorld(host, { root = REPO, label = 'qual' } = {}) {
|
|
|
127
127
|
}
|
|
128
128
|
export function worldEnv(w, extra = {}) {
|
|
129
129
|
const env = {};
|
|
130
|
-
|
|
130
|
+
// RUVNET_STOP_NUDGES is forwarded: with it stripped, a qualification run under `full` never executed the
|
|
131
|
+
// hooks that hook-shim.mjs runs only in that mode (grounding-turn-gate exited 0 unrun and "qualified").
|
|
132
|
+
for (const k of ['PATH', 'LANG', 'LC_ALL', 'SHELL', 'USER', 'RUVNET_STOP_NUDGES']) if (process.env[k] !== undefined) env[k] = process.env[k];
|
|
131
133
|
env.PATH = `${path.dirname(process.execPath)}${path.delimiter}${env.PATH || '/usr/bin:/bin'}`;
|
|
132
134
|
Object.assign(env, { HOME: w.home, USERPROFILE: w.home, TMPDIR: w.tmp, CLAUDE_PROJECT_DIR: w.cwd, RUVNET_BRAIN_HOME: path.join(w.home, '.cache', 'ruvnet-brain') });
|
|
133
135
|
if (w.host === 'codex') env.CODEX_HOME = path.join(w.home, '.codex');
|
package/scripts/hook-qualify.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
CASES, HOSTS, auditWrites, fixturesFor, measureInjection, registrations, runCase, runConcurrent, runRepeat,
|
|
18
18
|
sandboxAvailable, staticFindings,
|
|
19
19
|
} from './hook-qualify-core.mjs';
|
|
20
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
20
21
|
|
|
21
22
|
function arg(name, dflt = null) {
|
|
22
23
|
const i = process.argv.indexOf(`--${name}`);
|
|
@@ -98,4 +99,4 @@ async function main() {
|
|
|
98
99
|
return rows.every((r) => r.pass) ? 0 : 1;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
if (
|
|
102
|
+
if (isDirectInvocation(import.meta.url)) main().then((c) => process.exit(c), (e) => { console.error(e); process.exit(2); });
|
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { automaticHookRetirementStatus } from '../bin/install.mjs';
|
|
5
5
|
import { continuityRegistrations } from '../plugin/scripts/continuity-hook-policy.mjs';
|
|
6
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
6
7
|
|
|
7
8
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
8
9
|
|
|
@@ -24,6 +25,6 @@ export function main() {
|
|
|
24
25
|
return 0;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
if (
|
|
28
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
28
29
|
process.exitCode = main();
|
|
29
30
|
}
|
|
@@ -5,6 +5,7 @@ import path from 'node:path';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { canonicalJson, digest } from './coverage-integrity.mjs';
|
|
7
7
|
import { HOST_MODES, MODE_HOSTS } from './host-install-matrix.mjs';
|
|
8
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
8
9
|
|
|
9
10
|
export const HOST_ADAPTER_FILES = Object.freeze([
|
|
10
11
|
'plugin/host-adapters/claude.json',
|
|
@@ -115,4 +116,4 @@ export function main(args = process.argv.slice(2)) {
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
if ((
|
|
119
|
+
if (isDirectInvocation(import.meta.url)) process.exitCode = main();
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import { canonicalJson, digest } from './coverage-integrity.mjs';
|
|
7
7
|
import { transactionIdFor } from './release-transaction.mjs';
|
|
8
8
|
import { CLAUDE_FABLE_5_ID, GPT_5_6_SOL_ID, LEGACY_REVIEWER_IDENTITIES } from './review-model-defaults.mjs';
|
|
9
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
9
10
|
const HEX40 = /^[a-f0-9]{40}$/;
|
|
10
11
|
const HEX64 = /^[a-f0-9]{64}$/;
|
|
11
12
|
const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
@@ -495,4 +496,4 @@ export function main(args = process.argv.slice(2), runtime = {}) {
|
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
498
|
|
|
498
|
-
if (
|
|
499
|
+
if (isDirectInvocation(import.meta.url)) process.exitCode = main();
|
|
@@ -35,6 +35,7 @@ import path from 'node:path';
|
|
|
35
35
|
import { fileURLToPath } from 'node:url';
|
|
36
36
|
import { storeRoot, storesAt, darkStores } from '../kb/store-root.mjs';
|
|
37
37
|
import { assertIsolatedMutationWorktree } from './worktree-integrity.mjs';
|
|
38
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
38
39
|
|
|
39
40
|
const ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
40
41
|
const OWNER = process.env.RUVNET_ORG_OWNER || 'ruvnet';
|
|
@@ -77,7 +78,7 @@ export function pendingRepos(orgRepos, root = storeRoot()) {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
const isMain = (() => {
|
|
80
|
-
try { return
|
|
81
|
+
try { return isDirectInvocation(import.meta.url); }
|
|
81
82
|
catch { return false; }
|
|
82
83
|
})();
|
|
83
84
|
|
package/scripts/ingest-repo.mjs
CHANGED
|
@@ -21,6 +21,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
21
21
|
import { fileURLToPath } from 'node:url';
|
|
22
22
|
import { FULL_HINTS, KEEP_DIRS } from './full-hints.mjs';
|
|
23
23
|
import { storeRoot } from '../kb/store-root.mjs';
|
|
24
|
+
import { repositoryNames } from '../kb/card-lane.mjs';
|
|
24
25
|
import { applyPrivateOverlay } from './private-overlay.mjs';
|
|
25
26
|
|
|
26
27
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
@@ -103,11 +104,20 @@ const ok = fs.existsSync(path.join(KB, `${kb}.big.rvf`))
|
|
|
103
104
|
// cannot reach it. 26 of 66 stores are in exactly that state. The 2026-08-12 incident (three repos
|
|
104
105
|
// ingested, all reporting success, none findable) was read as a path bug; the path was only half of
|
|
105
106
|
// it. A store with no card is BUILT AND DARK, and saying "searchable" of it is the product lying.
|
|
107
|
+
// ALIAS-AWARE, BECAUSE THE ROUTER IS (kb/store-root.mjs's darkStores(), same fix). A raw heading
|
|
108
|
+
// match against `kb` alone reports DARK for a store only reachable through an alias card — e.g.
|
|
109
|
+
// `metaharness` is built as `metaharness.big.rvf` but described under `## agent-harness-generator`.
|
|
110
|
+
// That exact false positive once caused a DUPLICATE `## metaharness` card to be hand-added, which
|
|
111
|
+
// collided with the alias card and broke routing outright (see kb/store-root.mjs's own account).
|
|
112
|
+
// This CLI is where a user/agent decides whether to write a new card off this message, so it is
|
|
113
|
+
// the highest-leverage place to get alias resolution right.
|
|
106
114
|
const carded = (() => {
|
|
115
|
+
let headings;
|
|
107
116
|
try {
|
|
108
|
-
|
|
109
|
-
|
|
117
|
+
const raw = fs.readFileSync(path.join(KB, 'capability-cards.md'), 'utf8');
|
|
118
|
+
headings = [...raw.matchAll(/^##\s+(\S+)\s*$/gm)].map((m) => m[1].toLowerCase());
|
|
110
119
|
} catch { return false; }
|
|
120
|
+
return repositoryNames(kb, KB).some((name) => headings.includes(String(name).toLowerCase()));
|
|
111
121
|
})();
|
|
112
122
|
// AN ARTIFACT WITH NO COMMITTED RECIPE IS NOT DURABLE WORK — it is a local side effect with a
|
|
113
123
|
// countdown on it. Proven overnight 2026-08-13 -> 08-14: a scheduled bundle apply extracted an
|
|
@@ -4,6 +4,7 @@ import { validateQualificationReceipt } from './release-qualification.mjs';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
7
8
|
|
|
8
9
|
export const EXCLUSION_POLICY = 'release-linux-v1';
|
|
9
10
|
|
|
@@ -67,7 +68,7 @@ export function buildQualifiedIntegrationEvidence(report, identity) {
|
|
|
67
68
|
qualificationReceiptSha256: report.receiptSha256, requirements: report.requirements };
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
const isCli =
|
|
71
|
+
const isCli = isDirectInvocation(import.meta.url);
|
|
71
72
|
if (isCli) {
|
|
72
73
|
const value = (name) => process.argv[process.argv.indexOf(name) + 1];
|
|
73
74
|
const build = process.argv.includes('--qualified') ? buildQualifiedIntegrationEvidence : buildIntegrationEvidence;
|
package/scripts/issue-fix.mjs
CHANGED
|
@@ -46,7 +46,8 @@ import path from 'node:path';
|
|
|
46
46
|
import os from 'node:os';
|
|
47
47
|
import { spawn, spawnSync } from 'node:child_process';
|
|
48
48
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
49
|
-
import { BOT_MARKER, OWNER_LOGIN } from './issue-watch.mjs';
|
|
49
|
+
import { BOT_MARKER, OWNER_LOGIN, ghJsonWithRetry } from './issue-watch.mjs';
|
|
50
|
+
import { isDirectInvocation } from '../plugin/scripts/entrypoint.mjs';
|
|
50
51
|
|
|
51
52
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
52
53
|
const REPO = 'stuinfla/ruvnet-brain';
|
|
@@ -118,28 +119,10 @@ export function executionPolicy(mode = 'unattended') {
|
|
|
118
119
|
throw new Error(`unsupported issue-fix mode: ${mode}`);
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// fix exactly one class (transient network), so retry exactly once, log the first failure, and
|
|
126
|
-
// still fail LOUD if it happens twice. Never a silent swallow.
|
|
127
|
-
let lastErr;
|
|
128
|
-
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
129
|
-
const res = spawnSync(GH_BIN, args, { encoding: 'utf8' });
|
|
130
|
-
if (res.status === 0) return JSON.parse(res.stdout);
|
|
131
|
-
const err = (res.stderr || res.stdout || '').trim();
|
|
132
|
-
lastErr = new Error(`gh ${args.join(' ')} failed (exit ${res.status}): ${err}`);
|
|
133
|
-
const transient = /TLS handshake|unexpected EOF|timeout|ECONNRESET|ETIMEDOUT|EAI_AGAIN|connection refused|temporarily unavailable/i.test(err);
|
|
134
|
-
if (attempt === 1 && transient) {
|
|
135
|
-
console.error(`issue-fix: transient gh/network failure (${err.slice(0, 90)}) — retrying once in 20s`);
|
|
136
|
-
spawnSync('sleep', ['20']);
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
throw lastErr;
|
|
142
|
-
}
|
|
122
|
+
// Transient gh failures (TLS handshake, "error connecting to api.github.com", HTTP 502/503/504) are retried with
|
|
123
|
+
// backoff by the watcher's shared helper — one rule in one place (4.7.21: the old copy here missed the 1 a.m.
|
|
124
|
+
// "error connecting" blip and paged). Anything else still fails LOUD on the first attempt.
|
|
125
|
+
const ghJson = (args) => ghJsonWithRetry(args, { bin: GH_BIN, who: 'issue-fix' });
|
|
143
126
|
|
|
144
127
|
function loadState() {
|
|
145
128
|
try { return JSON.parse(fs.readFileSync(STATE_PATH, 'utf8')); } catch { return {}; }
|
|
@@ -555,4 +538,4 @@ async function main() {
|
|
|
555
538
|
process.exit(failedAttempt ? 1 : 0);
|
|
556
539
|
}
|
|
557
540
|
|
|
558
|
-
if (
|
|
541
|
+
if (isDirectInvocation(import.meta.url)) await main();
|