From d04e6efe1eae473f18eafec437f0633a1d39ede3 Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Wed, 22 Apr 2026 15:24:05 +0800 Subject: [PATCH] refactor(v0.17): README counts auto-generation via markers + regen script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminates README counts drift class (RULE 0.10 recurrence — 3rd drift in one week: RUST_CRATES 23→24, SKILLS 38→39, PROFILE_FULL 36→37, PROFILE_DEV 4→10, BLOCKS 73→78). Mechanism: HTML-comment markers wrap every auto-countable value: 24 16 marker types cover: RUST_CRATES, RUST/SHELL/TOTAL_PRIMITIVES, SKILLS, HOOKS, BLOCKS, AGENTS, BRIDGES, PROFILE_FULL/MCP/DEV/OPS/ FRONTEND/CORE, LBM_PORTS. scripts/regen-counts.sh (117 LOC, POSIX sh) — computes every count from source (MANIFEST.toml, Cargo.toml, find on skills/hooks/blocks/ manifests/bridges) and rewrites markers in place. --check mode (side-effect-free via mktemp+cmp+diff) exits 1 on drift. scripts/precommit-counts-check.sh (26 LOC) — invokes regen-counts --check, blocks commit on drift with fix-it hint. README gains 'Regenerating counts' subsection documenting both commands and pre-commit wiring. No Python/jq/yq hard deps. macOS /bin/sh compat (3.2-era). Idempotent. Constructor Pattern: largest script 117 LOC (<120), largest awk fn 10 LOC (<30). Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 55 ++++++++------ scripts/precommit-counts-check.sh | 26 +++++++ scripts/regen-counts.sh | 117 ++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 22 deletions(-) create mode 100755 scripts/precommit-counts-check.sh create mode 100755 scripts/regen-counts.sh diff --git a/README.md b/README.md index c296bb5..05a4e38 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,9 @@ Thanks. ## What it is -KeiSeiKit is a comprehensive drop-in toolkit for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, 9 pre-wired PreToolUse/PostToolUse hooks (three of them dedicated to RULE 0.14 session self-audit), 38 portable skills (including an interactive `/new-agent` wizard, 10 hub-and-spoke pipelines, and the `/self-audit` retrospective skill), **23 Rust primitive crates**, 13 opt-in shell primitives (plus 3 always-copied sleep-sync helpers), and 11 cross-tool bridge templates. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit. +KeiSeiKit is a comprehensive drop-in toolkit for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, 9 pre-wired PreToolUse/PostToolUse hooks (three of them dedicated to RULE 0.14 session self-audit), 39 portable skills (including an interactive `/new-agent` wizard, 10 hub-and-spoke pipelines, and the `/self-audit` retrospective skill), **24 Rust primitive crates**, 13 opt-in shell primitives (plus 3 always-copied sleep-sync helpers), and 11 cross-tool bridge templates. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit. -The kit is MIT-licensed and fully generic — install it on a fresh machine and you get a sane 12-agent fleet (implementers, critics, researchers, cost-guardians, and more — all namespaced under `kei-*` so they won't collide with your own same-named agents), a wizard for spinning up new project specialists, 10 pipeline skills that combine primitives end-to-end (`/compose-solution`, `/site-create`, `/schema-design`, `/observability-setup`, `/auth-setup`, `/api-design`, `/ci-scaffold`, `/test-matrix`, `/docs-scaffold`, `/new-project`, `/vm-provision`), and a build pipeline that keeps every agent derivable from its manifest. +The kit is MIT-licensed and fully generic — install it on a fresh machine and you get a sane 12-agent fleet (implementers, critics, researchers, cost-guardians, and more — all namespaced under `kei-*` so they won't collide with your own same-named agents), a wizard for spinning up new project specialists, 10 pipeline skills that combine primitives end-to-end (`/compose-solution`, `/site-create`, `/schema-design`, `/observability-setup`, `/auth-setup`, `/api-design`, `/ci-scaffold`, `/test-matrix`, `/docs-scaffold`, `/new-project`, `/vm-provision`), and a build pipeline that keeps every agent derivable from its manifest. ## Prerequisites @@ -67,7 +67,7 @@ cd KeiSeiKit 5. Builds the Rust assembler (`cargo build --release` in `_assembler/`) 6. If any Rust primitive is in the selected profile: writes a scoped workspace `Cargo.toml` listing ONLY the installed crates, then `cargo build --release` 7. Generates agent `.md` files in-place with `AGENT_ROOT=~/.claude/agents assemble --in-place` -8. Copies the 10 hooks and 38 skills +8. Copies the 9 hooks and 39 skills After install, the only remaining step is merging `settings-snippet.json` into your `~/.claude/settings.json` to activate the hooks. You can do this automatically with `./install.sh --activate-hooks` or answer `y` at the end-of-install TTY prompt. @@ -88,16 +88,16 @@ By default `./install.sh` is **minimal** — agents + hooks + skills + bridges, |---|---|---|---| | `minimal` (default) | none | ~5s | ~2 MB | | `core` | `tomd` | ~5s | ~2 MB | -| `frontend` | 8 site tools: `mock-render`, `visual-diff`, `tokens-sync`, `design-scrape`, `live-preview`, `figma-tokens`, `frontend-inspect`, `screenshot-decode` | ~60s | ~80 MB | -| `ops` | 8 infra tools: `kei-ledger`, `ssh-check`, `firewall-diff`, `provision-hetzner`, `provision-vultr`, `harden-base`, `metrics-scrape`, `log-ship` | ~90s | ~50 MB | -| `dev` | 4 dev tools: `kei-migrate`, `kei-changelog`, `kei-ci-lint`, `kei-docs-scaffold` | ~60s | ~40 MB | -| `full` | everything (36 primitives) | ~5 min | ~200 MB | +| `frontend` | 8 site tools: `mock-render`, `visual-diff`, `tokens-sync`, `design-scrape`, `live-preview`, `figma-tokens`, `frontend-inspect`, `screenshot-decode` | ~60s | ~80 MB | +| `ops` | 8 infra tools: `kei-ledger`, `ssh-check`, `firewall-diff`, `provision-hetzner`, `provision-vultr`, `harden-base`, `metrics-scrape`, `log-ship` | ~90s | ~50 MB | +| `dev` | 10 dev tools: `kei-migrate`, `kei-changelog`, `kei-ci-lint`, `kei-docs-scaffold`, `kei-memory`, `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, `kei-store`, `kei-artifact` | ~60s | ~40 MB | +| `full` | everything (37 primitives) | ~5 min | ~200 MB | Examples: ```bash ./install.sh # minimal (no primitives) -./install.sh --profile=frontend # minimal + 8 site tools +./install.sh --profile=frontend # minimal + 8 site tools ./install.sh --profile=full # everything (old default behaviour) ./install.sh --add=kei-ledger # add a single primitive on top of current install ./install.sh --add=kei-ledger,ssh-check @@ -108,7 +108,7 @@ Examples: Profile resolution lives in `_primitives/MANIFEST.toml` — one `[primitive.]` entry per primitive plus a `[profile]` block. Edit the manifest to define new profiles without touching `install.sh`. -> **Migrating from a full install:** if you're re-running `install.sh` after an earlier version that installed all primitives unconditionally, the new default (`minimal`) will REMOVE them. To preserve the old behaviour explicitly, pass `--profile=full` (currently 36 primitives). +> **Migrating from a full install:** if you're re-running `install.sh` after an earlier version that installed all primitives unconditionally, the new default (`minimal`) will REMOVE them. To preserve the old behaviour explicitly, pass `--profile=full` (currently 37 primitives). > **Re-install disclaimer:** `install.sh` is idempotent for clean state but **overwrites kit-owned `_blocks/`, `_primitives/`, `_bridges/`, `_templates/`, `_assembler/`, `hooks/`, and `skills/` on re-run** — local modifications under those directories are backed up to `.bak-TIMESTAMP/` (or, for shared hook files, to `.bak-TIMESTAMP`). User-owned `_manifests/*.toml` are never overwritten. @@ -143,16 +143,16 @@ Interactive wizard: run `/hooks-control` — click-only picker that shows curren | Category | Count | Examples | |---|---:|---| -| Behavioral blocks | 73 | `baseline`, `evidence-grading`, `rule-math-first`, `stack-rust-axum`, `stack-react-vite`, `stack-sveltekit`, `stack-astro`, `deploy-modal`, `api-fal-ai`, ... | -| Generic agents (manifests) | 12 | `kei-code-implementer`, `kei-critic`, `kei-validator`, `kei-security-auditor`, `kei-architect`, `kei-researcher`, `kei-ml-implementer`, `kei-cost-guardian`, `kei-modal-runner`, ... | -| Hooks (PreToolUse / PostToolUse) | 9 | `assemble-agents`, `assemble-validate`, `no-hand-edit-agents`, `tomd-preread`, `agent-fork-logger`, `site-wysiwyd-check`, `session-end-dump`, `milestone-commit-hook`, `error-spike-detector` | -| Portable skills | 38 | `compose-solution`, `new-agent`, `new-project`, `site-create`, `schema-design`, `observability-setup`, `auth-setup`, `api-design`, `ci-scaffold`, `test-matrix`, `docs-scaffold`, `vm-provision`, ... | -| Primitives (Rust crates, opt-in) | 23 | `kei-ledger`, `kei-migrate`, `kei-changelog`, `ssh-check`, `firewall-diff`, `mock-render`, `visual-diff`, `tokens-sync`, `kei-memory`, `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, `kei-store`, `kei-router`, `kei-sage`, `kei-task`, `kei-chat-store`, `kei-crossdomain`, `kei-search-core`, `kei-content-store`, `kei-social-store`, `kei-curator`, `kei-auth` | -| Primitives (shell, opt-in via profile) | 13 | `tomd`, `design-scrape`, `live-preview`, `figma-tokens`, `frontend-inspect`, `screenshot-decode`, `metrics-scrape`, `log-ship`, `provision-hetzner`, `provision-vultr`, `harden-base`, `kei-ci-lint`, `kei-docs-scaffold` | +| Behavioral blocks | 78 | `baseline`, `evidence-grading`, `rule-math-first`, `stack-rust-axum`, `stack-react-vite`, `stack-sveltekit`, `stack-astro`, `deploy-modal`, `api-fal-ai`, ... | +| Generic agents (manifests) | 12 | `kei-code-implementer`, `kei-critic`, `kei-validator`, `kei-security-auditor`, `kei-architect`, `kei-researcher`, `kei-ml-implementer`, `kei-cost-guardian`, `kei-modal-runner`, ... | +| Hooks (PreToolUse / PostToolUse) | 9 | `assemble-agents`, `assemble-validate`, `no-hand-edit-agents`, `tomd-preread`, `agent-fork-logger`, `site-wysiwyd-check`, `session-end-dump`, `milestone-commit-hook`, `error-spike-detector` | +| Portable skills | 39 | `compose-solution`, `new-agent`, `new-project`, `site-create`, `schema-design`, `observability-setup`, `auth-setup`, `api-design`, `ci-scaffold`, `test-matrix`, `docs-scaffold`, `vm-provision`, ... | +| Primitives (Rust crates, opt-in) | 24 | `kei-ledger`, `kei-migrate`, `kei-changelog`, `ssh-check`, `firewall-diff`, `mock-render`, `visual-diff`, `tokens-sync`, `kei-memory`, `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, `kei-store`, `kei-router`, `kei-sage`, `kei-task`, `kei-chat-store`, `kei-crossdomain`, `kei-search-core`, `kei-content-store`, `kei-social-store`, `kei-curator`, `kei-auth` | +| Primitives (shell, opt-in via profile) | 13 | `tomd`, `design-scrape`, `live-preview`, `figma-tokens`, `frontend-inspect`, `screenshot-decode`, `metrics-scrape`, `log-ship`, `provision-hetzner`, `provision-vultr`, `harden-base`, `kei-ci-lint`, `kei-docs-scaffold` | | Shell helpers (always copied) | 3 | `kei-sleep-setup`, `kei-sleep-sync`, `kei-sleep-queue` (dormant until you run `/sleep-setup`) | -| Cross-tool bridges | 11 | Cursor legacy/MDC, Codex, Copilot, Windsurf, Junie, Continue, Gemini, Aider, Replit | +| Cross-tool bridges | 11 | Cursor legacy/MDC, Codex, Copilot, Windsurf, Junie, Continue, Gemini, Aider, Replit | -Of the 73 blocks, the **8 base blocks** (`baseline`, `evidence-grading`, `memory-protocol`, `rule-pre-dev-gate`, `rule-test-first`, `rule-error-budget`, `rule-double-audit`, `rule-math-first`) are referenced directly by the 12 shipped manifests. The remaining blocks (`stack-*`, `deploy-*`, `api-*`, `scraper-*`, `domain-*`) are a library consumed by the `/new-agent` wizard and the hub-and-spoke pipeline skills: when you compose a project specialist or spin up a site, the wizard / pipeline picks the appropriate blocks and emits artefacts that reference them. +Of the 78 blocks, the **8 base blocks** (`baseline`, `evidence-grading`, `memory-protocol`, `rule-pre-dev-gate`, `rule-test-first`, `rule-error-budget`, `rule-double-audit`, `rule-math-first`) are referenced directly by the 12 shipped manifests. The remaining blocks (`stack-*`, `deploy-*`, `api-*`, `scraper-*`, `domain-*`) are a library consumed by the `/new-agent` wizard and the hub-and-spoke pipeline skills: when you compose a project specialist or spin up a site, the wizard / pipeline picks the appropriate blocks and emits artefacts that reference them. **Cognitive mode blocks** (`_blocks/mode-*.md`) are composable behavioural skews — `mode-skeptic`, `mode-devils-advocate`, `mode-minimalist`, `mode-maximalist`, `mode-first-principles`. Add any combination to an agent's manifest `blocks = [...]` list to stack the mode. Modes compose: `mode-skeptic` + `mode-minimalist` gives you an adversarial pruner; `mode-devils-advocate` + `mode-first-principles` gives a constraint-driven steel-manner. See `_blocks/README.md` for the full list. @@ -283,7 +283,7 @@ Requires the new `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, ## Primitives (Rust) -`_primitives/_rust/` is a Cargo workspace with 23 single-binary crates (v0.13.0 added 4 deep-sleep primitives; v0.14.0 added 10 LBM-port MCP crates; v0.14.2 removed `genesis-scan` — internal-only tool, not shipped publicly). `install.sh` builds `--release` for the subset selected by the active profile and drops binaries at `~/.claude/agents/_primitives/_rust/target/release/`. +`_primitives/_rust/` is a Cargo workspace with 24 single-binary crates (v0.13.0 added 4 deep-sleep primitives; v0.14.0 added 10 LBM-port MCP crates; v0.14.2 removed `genesis-scan` — internal-only tool, not shipped publicly). `install.sh` builds `--release` for the subset selected by the active profile and drops binaries at `~/.claude/agents/_primitives/_rust/target/release/`. | Crate | Purpose | |---|---| @@ -334,7 +334,7 @@ Requires the new `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, Block edit (_blocks/.md) <-- triggers rebuild of ALL agents ``` -9 hooks enforce the pipeline (6 pipeline + 3 session-audit): +9 hooks enforce the pipeline (6 pipeline + 3 session-audit): - **`assemble-agents`** (PostToolUse, Write/Edit) — rebuilds the affected agent(s) whenever a manifest or a block changes. No manual rebuild needed. - **`assemble-validate`** (PreToolUse, Bash) — blocks `git commit` inside `~/.claude` if any manifest fails validation. Keeps the repo in a buildable state at all times. @@ -346,6 +346,17 @@ Requires the new `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, - **`milestone-commit-hook`** (PostToolUse, Bash) — RULE 0.14 self-audit: appends a one-line session summary to `~/.claude/memory/audit-backlog.md` on every `feat:`/`refactor:`/merge commit. - **`error-spike-detector`** (PostToolUse, any tool) — RULE 0.14 self-audit: tags + logs the pattern when 3+ errors occur within the last 20 tool calls. +## Regenerating counts + +Every number above (crates / skills / hooks / blocks / primitives / profile sizes) is wrapped in an HTML-comment marker — `24` — and regenerated from sources of truth (`_primitives/MANIFEST.toml`, `_primitives/_rust/Cargo.toml`, filesystem walks). No more drift when a primitive or skill is added. + +```bash +./scripts/regen-counts.sh # rewrite README.md in place +./scripts/regen-counts.sh --check # exit 1 if drift detected (no writes) +``` + +Pre-commit gate: `scripts/precommit-counts-check.sh` — wire it into your hook manager (or symlink into `.git/hooks/pre-commit`) to block commits when README counts drift from the sources. + ## Adding custom blocks Blocks are plain markdown in `~/.claude/agents/_blocks/`. To add one: @@ -381,7 +392,7 @@ All kit agents are namespaced under `kei-*` so they won't collide with your own ## Cross-tool bridges -KeiSeiKit ships 11 verified tool-bridge templates under `_bridges/`. Render them into any project and the same Constructor-Pattern ruleset is visible to every AI coding tool you use — no drift, one source of truth. +KeiSeiKit ships 11 verified tool-bridge templates under `_bridges/`. Render them into any project and the same Constructor-Pattern ruleset is visible to every AI coding tool you use — no drift, one source of truth. **Tools covered:** @@ -400,8 +411,8 @@ KeiSeiKit ships 11 verified tool-bridge templates under `_bridges/`. Render them **Three ways to generate:** -1. **At install time** — `./install.sh --with-bridges` renders all 11 into `$PWD` after the normal install completes. Skipped if `$PWD` is the KeiSeiKit repo itself. -2. **From the `/new-agent` wizard** — Phase 8 asks click-only whether to generate all 11, just `AGENTS.md`, or skip. +1. **At install time** — `./install.sh --with-bridges` renders all 11 into `$PWD` after the normal install completes. Skipped if `$PWD` is the KeiSeiKit repo itself. +2. **From the `/new-agent` wizard** — Phase 8 asks click-only whether to generate all 11, just `AGENTS.md`, or skip. 3. **Manually, any time** — `~/.claude/agents/_bridges/emit.sh ` (the install copies `_bridges/` into your agent fleet dir). Add `--only ` to restrict to a single file. All paths are idempotent: existing bridge files in the project are skipped, never overwritten. See `_bridges/README.md` for the full template→output-path table. diff --git a/scripts/precommit-counts-check.sh b/scripts/precommit-counts-check.sh new file mode 100755 index 0000000..f7427d1 --- /dev/null +++ b/scripts/precommit-counts-check.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# precommit-counts-check.sh — pre-commit gate for README count drift. +# Runs scripts/regen-counts.sh --check; exits non-zero on drift. +# Install: ln -s ../../scripts/precommit-counts-check.sh .git/hooks/pre-commit +# or add to your hook manager of choice. + +set -eu + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +REGEN="$ROOT/scripts/regen-counts.sh" + +[ -x "$REGEN" ] || { + printf 'precommit-counts-check: %s not executable\n' "$REGEN" >&2 + exit 2 +} + +if "$REGEN" --check; then + exit 0 +fi + +cat >&2 <<'EOF' + +Counts drift detected in README.md. +Run: ./scripts/regen-counts.sh && git add README.md +EOF +exit 1 diff --git a/scripts/regen-counts.sh b/scripts/regen-counts.sh new file mode 100755 index 0000000..e7d83c7 --- /dev/null +++ b/scripts/regen-counts.sh @@ -0,0 +1,117 @@ +#!/bin/sh +# regen-counts.sh — regenerate README.md counts from sources of truth. +# Markers: VAL +# Sources: _primitives/MANIFEST.toml, _primitives/_rust/Cargo.toml, filesystem. +# Usage: ./scripts/regen-counts.sh [--check] +# POSIX sh; no arrays, no bashisms; no yq/jq/python hard deps. + +set -eu + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +README="$ROOT/README.md" +MANIFEST="$ROOT/_primitives/MANIFEST.toml" +CARGO="$ROOT/_primitives/_rust/Cargo.toml" + +die() { printf 'regen-counts: %s\n' "$*" >&2; exit 2; } + +count_rust_crates() { + awk ' + /^\[workspace\]/ { in_ws=1; next } + /^\[/ { in_ws=0 } + in_ws && /members *= *\[/ { in_arr=1 } + in_arr { total += gsub(/"[^"]+"/, "&"); if (index($0, "]")) in_arr=0 } + END { print total+0 } + ' "$CARGO" +} + +count_primitive_kind() { + awk -v want="$1" ' + /^\[primitive\./ { in_block=1; next } + /^\[/ { in_block=0 } + in_block && $0 ~ "^kind *= *\"" want "\"" { n++; in_block=0 } + END { print n+0 } + ' "$MANIFEST" +} + +count_profile() { + awk -v key="$1" ' + /^\[profile\]/ { in_p=1; next } + /^\[/ { in_p=0 } + in_p && $1 == key && $2 == "=" { + line=$0; sub(/^[^\[]*\[/, "", line); sub(/\].*$/, "", line) + print gsub(/"[^"]+"/, "&", line) + 0; exit + } + ' "$MANIFEST" +} + +count_files() { eval "$1" | wc -l | tr -d ' '; } + +RUST_CRATES=$(count_rust_crates) +RUST_PRIMITIVES=$(count_primitive_kind rust) +SHELL_PRIMITIVES=$(count_primitive_kind shell) +TOTAL_PRIMITIVES=$((RUST_PRIMITIVES + SHELL_PRIMITIVES)) +SKILLS=$(count_files "find '$ROOT/skills' -maxdepth 2 -name SKILL.md") +HOOKS=$(count_files "find '$ROOT/hooks' -maxdepth 1 -name '*.sh'") +BLOCKS=$(count_files "find '$ROOT/_blocks' -maxdepth 1 -name '*.md' -not -name README.md") +AGENTS=$(count_files "find '$ROOT/_manifests' -maxdepth 1 -name 'kei-*.toml'") +BRIDGES=$(count_files "find '$ROOT/_bridges' -maxdepth 1 \( -name '*.tmpl' -o -name '*.mdc' \)") +PROFILE_FULL=$(count_profile full) +PROFILE_MCP=$(count_profile mcp) +PROFILE_DEV=$(count_profile dev) +PROFILE_OPS=$(count_profile ops) +PROFILE_FRONTEND=$(count_profile frontend) +PROFILE_CORE=$(count_profile core) +LBM_PORTS=10 # hand-maintained: v0.14 LBM port semantic group + +[ "$RUST_CRATES" = "$RUST_PRIMITIVES" ] || \ + printf 'regen-counts: WARN Cargo members (%s) != MANIFEST rust kind (%s)\n' \ + "$RUST_CRATES" "$RUST_PRIMITIVES" >&2 + +apply_markers() { + awk \ + -v m_rc="$RUST_CRATES" -v m_rp="$RUST_PRIMITIVES" \ + -v m_sp="$SHELL_PRIMITIVES" -v m_tp="$TOTAL_PRIMITIVES" \ + -v m_sk="$SKILLS" -v m_hk="$HOOKS" \ + -v m_bl="$BLOCKS" -v m_ag="$AGENTS" \ + -v m_br="$BRIDGES" \ + -v m_pf="$PROFILE_FULL" -v m_pm="$PROFILE_MCP" \ + -v m_pd="$PROFILE_DEV" -v m_po="$PROFILE_OPS" \ + -v m_pr="$PROFILE_FRONTEND" -v m_pc="$PROFILE_CORE" \ + -v m_lb="$LBM_PORTS" ' + function sub_marker(name, val, re) { + re = "[^<]*" + gsub(re, "" val "") + } + { + sub_marker("RUST_CRATES", m_rc); sub_marker("RUST_PRIMITIVES", m_rp) + sub_marker("SHELL_PRIMITIVES", m_sp); sub_marker("TOTAL_PRIMITIVES", m_tp) + sub_marker("SKILLS", m_sk); sub_marker("HOOKS", m_hk) + sub_marker("BLOCKS", m_bl); sub_marker("AGENTS", m_ag) + sub_marker("BRIDGES", m_br); sub_marker("PROFILE_FULL", m_pf) + sub_marker("PROFILE_MCP", m_pm); sub_marker("PROFILE_DEV", m_pd) + sub_marker("PROFILE_OPS", m_po); sub_marker("PROFILE_FRONTEND", m_pr) + sub_marker("PROFILE_CORE", m_pc); sub_marker("LBM_PORTS", m_lb) + print + } + ' +} + +mode="${1:-write}" +[ -f "$README" ] || die "README.md not found at $README" + +tmp=$(mktemp -t regen-counts.XXXXXX) || die "mktemp failed" +trap 'rm -f "$tmp"' EXIT INT TERM +apply_markers <"$README" >"$tmp" + +if [ "$mode" = "--check" ]; then + if cmp -s "$README" "$tmp"; then + echo "regen-counts: no drift"; exit 0 + fi + echo "regen-counts: DRIFT DETECTED" >&2 + diff -u "$README" "$tmp" >&2 || true + exit 1 +fi + +cp "$tmp" "$README" +printf 'regen-counts: README updated (crates=%s skills=%s hooks=%s blocks=%s prims=%s)\n' \ + "$RUST_CRATES" "$SKILLS" "$HOOKS" "$BLOCKS" "$TOTAL_PRIMITIVES"