diff --git a/README.md b/README.md index 260d945..9023321 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), 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. +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 @@ -50,33 +50,7 @@ The kit is MIT-licensed and fully generic — install it on a fresh machine and `install.sh` checks only the deps relevant to the selected profile and soft-warns once per missing tool. -## Plugin install (v0.16+, recommended) - -If you have Claude Code 2026.04+ (plugin format supported), install via the Claude Code plugin system: - -```bash -# 1. Add this marketplace (one-time) -/plugin marketplace add KeiSei84/KeiSeiKit - -# 2. Install the plugin -/plugin install keisei@keisei-marketplace - -# Later: update or uninstall -/plugin update keisei -/plugin uninstall keisei@keisei-marketplace -``` - -The plugin layout matches the Anthropic plugin spec — all agents, skills, hooks, and the MCP server are registered automatically. No need to touch `~/.claude/settings.json` or run `install.sh`. - -**What the plugin registers:** agents in `agents/`, skills in `skills/*/SKILL.md`, hooks via `hooks/hooks.json`, MCP server via `.mcp.json`. Everything is sandboxed to the plugin install location via `${CLAUDE_PLUGIN_ROOT}` — no pollution of your personal `~/.claude/` config. - -**What the plugin does NOT install automatically:** the 24 Rust primitive crates. Those need `cargo` and are built per-profile via the classic installer below. If you want the Rust primitives (tomd, kei-ledger, provision-hetzner, etc.), fall back to the classic install path. A future plugin version may ship pre-built release binaries for common platforms. - -See [`PLUGIN.md`](./PLUGIN.md) for the full plugin layout, prerequisites, and known limitations. - -## Classic install (git clone + install.sh, still fully supported) - -For power users who want the Rust primitives, full control over the profile, or who don't have plugin-capable Claude Code yet: +## Install ```bash git clone KeiSeiKit @@ -84,36 +58,6 @@ cd KeiSeiKit ./install.sh # profile=minimal (default, no primitives) ``` -### Pre-built binaries (no Rust toolchain needed) - -From v0.16.0 on, every tagged release attaches pre-built Rust binaries, -so you can skip the local `cargo build --release` step entirely. -Download the archive for your platform from -[Releases](https://github.com/KeiSei84/KeiSeiKit/releases) and extract -it into the primitives workspace **before** running `./install.sh`: - -- `keisei-x86_64-unknown-linux-gnu.tar.gz` — Linux x86_64 -- `keisei-aarch64-unknown-linux-gnu.tar.gz` — Linux ARM64 (best-effort) -- `keisei-x86_64-apple-darwin.tar.gz` — macOS Intel -- `keisei-aarch64-apple-darwin.tar.gz` — macOS Apple Silicon - -```bash -# after cloning the kit: -mkdir -p _primitives/_rust/target/release -tar xzf keisei-.tar.gz -C _primitives/_rust/target/release -export KEI_SKIP_RUST_BUILD=1 # optional — forces skip -./install.sh --profile=full -``` - -`install.sh` auto-detects pre-built binaries in -`_primitives/_rust/target/release/` and skips the primitives -`cargo build --workspace --release` when they are present. Set -`KEI_SKIP_RUST_BUILD=1` to force-skip regardless of detection (useful on -air-gapped machines). Each release also ships a `*.sha256` checksum -file — verify with `sha256sum -c keisei-.tar.gz.sha256` before -extracting. Release notes are auto-generated from the git history by -`kei-changelog` — see [`CHANGELOG.md`](./CHANGELOG.md) for the full log. - `install.sh` is idempotent. It: 1. Creates `~/.claude/agents/{_blocks,_manifests,_primitives,_bridges,_templates,_assembler,_generated}`, `~/.claude/hooks`, `~/.claude/skills` @@ -121,9 +65,9 @@ extracting. Release notes are auto-generated from the git history by 3. Copies primitives ONLY for the selected profile (default: `minimal` = none). Tracks installed set in `~/.claude/agents/_primitives/.installed`. 4. Copies generic manifests (skips if you already have a manifest with that name) 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` — **skipped when `KEI_SKIP_RUST_BUILD=1` or pre-built binaries are detected in `target/release/`** +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 9 hooks and 39 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. @@ -144,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 (37 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 @@ -164,22 +108,22 @@ 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 37 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. ## Runtime hook controls -Every kit-shipped hook (v0.15.1+) honours two env vars so you can silence noise or isolate a failure without editing `~/.claude/settings.json`: +Every kit-shipped hook (v0.14.2+) honours two env vars so you can silence noise or isolate a failure without editing `~/.claude/settings.json`: -- `KEI_DISABLED_HOOKS` — comma- or space-list of hook base names (no `.sh`), e.g. `KEI_DISABLED_HOOKS=site-wysiwyd-check,milestone-commit-hook`. Matching is **tokenized exact-match** (v0.15.1 fix — prior versions used substring-glob which let any value containing `all` disable every hook). The literal `all` token still disables every hook. +- `KEI_DISABLED_HOOKS` — comma- or space-list of hook base names (no `.sh`), e.g. `KEI_DISABLED_HOOKS=site-wysiwyd-check,milestone-commit-hook`. The literal `all` disables every hook. - `KEI_HOOK_PROFILE` — one of `full` (default), `advisory-off`, `minimal`, `off`. | Profile | What stays on | |---|---| | `full` (default) | Every hook | | `advisory-off` | Disables pure-stderr advisories (`recurrence-suggest`, `citation-verify`, `error-spike-detector`, `milestone-commit-hook`). Safety gates stay on. | -| `minimal` | Only the four kit-shipped hooks that are either structural integrity (`no-hand-edit-agents`, `assemble-validate`) or observability-critical under RULE 0.12 / RULE 0.14 (`agent-fork-logger`, `session-end-dump`). Every other kit hook is off. User-global safety hooks such as `no-github-push`, `secrets-guard`, `genesis-leak-guard`, or `git-pre-commit-genesis` are not shipped by the kit but are respected when they are present in `~/.claude/hooks/`. | +| `minimal` | Only safety-critical: `no-github-push`, `genesis-leak-guard`, `no-hand-edit-agents`, `secrets-guard`, `assemble-validate`, `git-pre-commit-genesis`. Everything else off. | | `off` | Every hook off — escape hatch for debugging hook interactions. | ```bash @@ -199,16 +143,16 @@ Interactive wizard: run `/hooks-control` — click-only picker that shows curren | Category | Count | Examples | |---|---:|---| -| Behavioral blocks | 77 | `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`, `kei-artifact` | -| 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 | 79 | `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 77 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 79 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. @@ -339,7 +283,7 @@ Requires the new `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, ## Primitives (Rust) -`_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; v0.15.0 added `kei-artifact` for typed review-handoff). `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 | |---|---| @@ -356,7 +300,6 @@ Requires the new `kei-conflict-scan`, `kei-refactor-engine`, `kei-graph-check`, | `kei-refactor-engine` | v0.13.0 — consumes `kei-conflict-scan` JSON; emits plan markdown + auto-resolve review markdown (NOT a unified diff; v0.14.1 retraction) | | `kei-graph-check` | v0.13.0 — post-refactor wikilink + handoff + block-ref resolver gate | | `kei-store` | v0.13.0 — memory-repo backend abstraction (GitHub / Forgejo / Gitea / Filesystem / S3) | -| `kei-artifact` | v0.15.0 — typed artifact handoff pipeline (schema-validated content pass-between agents) | ## Primitives (shell) @@ -391,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. @@ -403,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: @@ -438,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:** @@ -457,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"