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,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rvbc
|
|
3
|
+
description: Open the RuvNet Brain Console in Claude Code and Codex when the user says "Configure RuvNet Brain", mentions "rvbc", asks for the Brain Console, or wants to configure or inspect RuvNet Brain. Claude Code supports /rvbc; Codex invokes the native $ruvnet-brain:rvbc skill.
|
|
4
|
+
updated: 2026-07-30
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# RuvNet Brain Console
|
|
8
|
+
|
|
9
|
+
“Configure RuvNet Brain” opens this Console in Claude Code and Codex. Claude Code also supports
|
|
10
|
+
`/rvbc`; Codex invokes this skill as `$ruvnet-brain:rvbc` because custom plugin slash commands are
|
|
11
|
+
not part of the Codex CLI slash-command surface.
|
|
12
|
+
|
|
13
|
+
1. Say one short sentence: "Opening it now; it scans live while you watch."
|
|
14
|
+
2. Resolve the installed runtime at
|
|
15
|
+
`${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
16
|
+
A current-repository `scripts/onboarding-console.mjs` is allowed only for an explicit developer
|
|
17
|
+
checkout. Never fall back to a guessed `~/Code` path.
|
|
18
|
+
3. Run `node <resolved-script> --serve --open` in the background.
|
|
19
|
+
4. Give the URL immediately. Do not promise a duration; the page reports its own scan progress.
|
|
20
|
+
|
|
21
|
+
An already-running server is success. The Console is read-only until the user chooses an action;
|
|
22
|
+
every change must be explained and reversible. If the script cannot be located or the server fails,
|
|
23
|
+
report the exact failure plainly instead of claiming the Console opened.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: savings
|
|
3
|
+
description: Show the MetaHarness routing ledger inline — which model each task was routed to, what it displaced, and the percentage + dollars saved — plus the learned router's training state. Use when the user says "savings", "show my savings", "metaharness report", "metaharness/report", "routing report", "routing receipts", "who is the router choosing", "how much has routing saved me", "is the meta harness working", or "show me the routing". All numbers come from the real receipts log; never fake or extrapolate a number.
|
|
4
|
+
updated: 2026-07-13
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Savings — the MetaHarness routing ledger, inline
|
|
8
|
+
|
|
9
|
+
Show the user their routing wins the way a bank statement shows transactions: real rows, real
|
|
10
|
+
totals, zero vibes. Everything below comes from live artifacts on their machine; if a file is
|
|
11
|
+
missing or empty, say exactly that — an honest "nothing routed yet" builds more trust than a
|
|
12
|
+
padded number.
|
|
13
|
+
|
|
14
|
+
## Steps (run these, verbatim — then render)
|
|
15
|
+
|
|
16
|
+
1. **The ledger**:
|
|
17
|
+
`node scripts/metaharness-receipts.mjs`
|
|
18
|
+
(falls back to `~/.claude/metaharness/routing-receipts.jsonl` raw if the script is absent —
|
|
19
|
+
the plugin repo root or the installed package both carry it under `scripts/`).
|
|
20
|
+
2. **The learner's state**:
|
|
21
|
+
`node -e "import(REPO+'/scripts/metaharness-router.mjs').then(m=>{const r=m.loadLabelledRows();console.log(JSON.stringify({labels:r.rows.length,needed:m.MIN_LABELS}))})"`
|
|
22
|
+
3. Optional, if the user asks who decides: run one live decision
|
|
23
|
+
`node scripts/model-router-engine.mjs --prompt "<their current task>"` and quote `routedBy`.
|
|
24
|
+
|
|
25
|
+
## Render
|
|
26
|
+
|
|
27
|
+
The receipts script already draws the full card (percentage-first headline + spent-vs-unrouted
|
|
28
|
+
bar + audit table) — **show its output verbatim in a code block**; do not re-format or re-total
|
|
29
|
+
it. Then append the learner's state on two lines:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
🧠 Learned router: <routedBy state>
|
|
33
|
+
<labels>/<needed> outcome examples → <"learning-routed decisions live" | "cold-start: static
|
|
34
|
+
tiers deciding (honest fallback) — N more outcomes to go">
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Hard rules
|
|
38
|
+
|
|
39
|
+
- **Never fake a number.** Every dollar figure must trace to a receipt row. If `token_source`
|
|
40
|
+
says estimated, the totals line keeps the script's own "est." qualifier.
|
|
41
|
+
- **Print the honest router state.** If the learner is below MIN_LABELS, say cold-start plainly —
|
|
42
|
+
the fallback tiers still save money and that is a true story worth telling.
|
|
43
|
+
- **One screen.** Cap the table at 10 most-recent rows; state "+N earlier rows" if truncated.
|
|
44
|
+
- After showing the ledger, offer ONE next action, not a menu: if labels < 20, offer the
|
|
45
|
+
calibration run ("want me to train it up with a $0 calibration batch?"); otherwise offer
|
|
46
|
+
nothing.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: whats-new
|
|
3
|
+
description: Explain what is new in the installed RuvNet Brain release from live version metadata and the curated release notes. Use for "/whats-new", "what's new", "what changed", "new release", or "show me the latest Brain improvements". Never claim a 4.0 version unless the installed version actually starts with 4.
|
|
4
|
+
updated: 2026-07-28
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# What is new
|
|
8
|
+
|
|
9
|
+
Ground the answer in files that exist now; do not recite release claims from memory.
|
|
10
|
+
|
|
11
|
+
1. Read the installed plugin version from `.codex-plugin/plugin.json` relative to this skill's
|
|
12
|
+
plugin root. If that is unavailable, read the current checkout's `plugin/.codex-plugin/plugin.json`.
|
|
13
|
+
2. Locate `docs/RELEASE-NOTES-4.0.md` in the current repository, then
|
|
14
|
+
`~/Code/ruvnet-brain/docs/RELEASE-NOTES-4.0.md`. Read it before summarizing.
|
|
15
|
+
3. State the installed version exactly. Do not say the user is on 4.0 unless it starts with `4.`.
|
|
16
|
+
For a 3.9 development version, describe verified items as "4.0-line enhancements landing in
|
|
17
|
+
3.9.x", using the release note's own status language.
|
|
18
|
+
4. Summarize only the curated highlights and their evidence status. Never invent metrics or turn
|
|
19
|
+
newly collecting measurement into proof of improvement.
|
|
20
|
+
5. End by offering to open the Console through the native `brain-console` workflow.
|
|
21
|
+
|
|
22
|
+
If the release notes are missing, say they are unavailable and do not fabricate a highlight.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* adr-backfill.mjs — lift status and dates into frontmatter where tooling can read them.
|
|
4
|
+
*
|
|
5
|
+
* THE GAP, measured 2026-07-22: 12 of 32 ADRs carried NO frontmatter status and NO dates, and 9
|
|
6
|
+
* more had a creation date but no `updated`. The owner's requirement is exact: *"One thing I ALWAYS
|
|
7
|
+
* want you to do is indicate in an ADR what the status is... they should have a time and date
|
|
8
|
+
* stamped on when they were initially written and a time and date stamped on the last time they
|
|
9
|
+
* were updated and why. That way I know I'm never looking at out-of-date documents."*
|
|
10
|
+
*
|
|
11
|
+
* NOTHING HERE IS INVENTED, and that constraint is the whole design:
|
|
12
|
+
*
|
|
13
|
+
* status LIFTED from the document's own body. All 12 already say `**Status**: Accepted (date)`
|
|
14
|
+
* — the information was never missing, it just sat where no tool could read it. A status
|
|
15
|
+
* is a judgement; deriving one from git would be fabrication, so a document that does
|
|
16
|
+
* not state its own status is REPORTED and skipped, never guessed at.
|
|
17
|
+
* date LIFTED from the body's `**Date**:`, falling back to git's first-commit date.
|
|
18
|
+
* updated DERIVED from `git log -1` — the last commit that actually touched the file. A typed
|
|
19
|
+
* date can be wrong; a git object cannot.
|
|
20
|
+
*
|
|
21
|
+
* Every written value is therefore traceable to either the document itself or the repository's
|
|
22
|
+
* history. This matters because a fabricated timestamp is worse than a missing one: a missing
|
|
23
|
+
* stamp is visibly unknown, while a wrong stamp is confidently misleading — the exact failure mode
|
|
24
|
+
* this project has paid for repeatedly.
|
|
25
|
+
*
|
|
26
|
+
* node scripts/adr-backfill.mjs report what WOULD change (default; writes nothing)
|
|
27
|
+
* node scripts/adr-backfill.mjs --apply write it
|
|
28
|
+
*/
|
|
29
|
+
import fs from 'node:fs';
|
|
30
|
+
import path from 'node:path';
|
|
31
|
+
import { execFileSync } from 'node:child_process';
|
|
32
|
+
|
|
33
|
+
const REPO = path.resolve(import.meta.dirname, '..');
|
|
34
|
+
const ADR_DIR = path.join(REPO, 'docs', 'adr');
|
|
35
|
+
const apply = process.argv.includes('--apply');
|
|
36
|
+
|
|
37
|
+
const git = (args) => {
|
|
38
|
+
try { return execFileSync('git', args, { cwd: REPO, encoding: 'utf8' }).trim(); }
|
|
39
|
+
catch { return ''; }
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** First-commit date — the honest "created", when the body does not state one. */
|
|
43
|
+
const gitCreated = (rel) =>
|
|
44
|
+
(git(['log', '--follow', '--diff-filter=A', '--format=%ad', '--date=short', '--', rel]).split('\n').filter(Boolean).pop() || '');
|
|
45
|
+
|
|
46
|
+
/** Last commit that touched the file — the honest "updated". */
|
|
47
|
+
const gitUpdated = (rel) => git(['log', '-1', '--format=%ad', '--date=short', '--', rel]);
|
|
48
|
+
|
|
49
|
+
const VALID = ['Proposed', 'Accepted', 'Implemented', 'Superseded', 'Deprecated'];
|
|
50
|
+
|
|
51
|
+
function parseBody(src) {
|
|
52
|
+
// `**Status**: Accepted (2026-06-27)` → Accepted, 2026-06-27
|
|
53
|
+
const sm = src.match(/^\*\*Status\*\*:\s*([A-Za-z]+)(?:\s*\((\d{4}-\d{2}-\d{2})\))?/m);
|
|
54
|
+
const dm = src.match(/^\*\*Date\*\*:\s*(\d{4}-\d{2}-\d{2})/m);
|
|
55
|
+
const status = sm && VALID.find((v) => v.toLowerCase() === sm[1].toLowerCase());
|
|
56
|
+
return { status: status || null, statusDate: sm?.[2] || null, date: dm?.[1] || null };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function frontmatter(src) {
|
|
60
|
+
const lines = src.split('\n');
|
|
61
|
+
if (lines[0]?.trim() !== '---') return null;
|
|
62
|
+
const end = lines.findIndex((l, i) => i > 0 && l.trim() === '---');
|
|
63
|
+
if (end < 0) return null;
|
|
64
|
+
const keys = {};
|
|
65
|
+
for (let i = 1; i < end; i++) {
|
|
66
|
+
const m = lines[i].match(/^(\w+):\s*(.*)$/);
|
|
67
|
+
if (m) keys[m[1]] = m[2];
|
|
68
|
+
}
|
|
69
|
+
return { keys, end, lines };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const f of fs.readdirSync(ADR_DIR).filter((n) => /^\d{4}-.*\.md$/.test(n)).sort()) {
|
|
74
|
+
const rel = path.join('docs', 'adr', f);
|
|
75
|
+
const abs = path.join(ADR_DIR, f);
|
|
76
|
+
const src = fs.readFileSync(abs, 'utf8');
|
|
77
|
+
const fm = frontmatter(src);
|
|
78
|
+
if (!fm) { results.push({ f, skip: 'no frontmatter block to extend' }); continue; }
|
|
79
|
+
|
|
80
|
+
const body = parseBody(src);
|
|
81
|
+
const need = {};
|
|
82
|
+
if (!fm.keys.status && body.status) need.status = body.status;
|
|
83
|
+
if (!fm.keys.date) { const d = body.date || body.statusDate || gitCreated(rel); if (d) need.date = d; }
|
|
84
|
+
if (!fm.keys.updated) { const u = gitUpdated(rel); if (u) need.updated = u; }
|
|
85
|
+
|
|
86
|
+
if (!fm.keys.status && !body.status) {
|
|
87
|
+
// A status is a judgement. Refuse to guess; report it so a human can decide.
|
|
88
|
+
results.push({ f, skip: 'no status stated anywhere — a human must set this, it cannot be derived' });
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (!Object.keys(need).length) { results.push({ f, ok: true }); continue; }
|
|
92
|
+
|
|
93
|
+
if (apply) {
|
|
94
|
+
const insert = Object.entries(need).map(([k, v]) => `${k}: ${v}`);
|
|
95
|
+
const out = [...fm.lines.slice(0, fm.end), ...insert, ...fm.lines.slice(fm.end)];
|
|
96
|
+
fs.writeFileSync(abs, out.join('\n'));
|
|
97
|
+
}
|
|
98
|
+
results.push({ f, need });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const changed = results.filter((r) => r.need);
|
|
102
|
+
const skipped = results.filter((r) => r.skip);
|
|
103
|
+
console.log(`\n ${results.length} ADR(s) · ${changed.length} ${apply ? 'updated' : 'would change'} · ${skipped.length} skipped · ${results.filter((r) => r.ok).length} already complete\n`);
|
|
104
|
+
for (const r of changed) console.log(` ${apply ? '✓' : '·'} ${r.f} +${Object.entries(r.need).map(([k, v]) => `${k}=${v}`).join(' +')}`);
|
|
105
|
+
for (const r of skipped) console.log(` ⚠ ${r.f} — ${r.skip}`);
|
|
106
|
+
if (!apply && changed.length) console.log(`\n Nothing written. Re-run with --apply.\n`);
|
|
107
|
+
else console.log('');
|