|
1 | 1 | #!/usr/bin/env bash |
2 | 2 | # |
3 | | -# bean installer (fallback to the plugin marketplace). |
4 | | -# Copies the bean skill + command into your Claude Code config, and the skill into |
5 | | -# your Codex config when present. Documentation-only: no dependencies, no servers. |
| 3 | +# bean installer — builds the Rust runtime and wires it into Claude Code (and Codex). |
| 4 | +# |
| 5 | +# What you get after this: |
| 6 | +# - the bean runtime binaries (bean-check, bean-verify, bean-run, bean-hook) built into ./bin |
| 7 | +# - the /bean skill installed |
| 8 | +# - a native Stop hook registered so bean COUPLES to execution: an agent can't finish a |
| 9 | +# bean-tracked task (one with a .bean/ ledger) until the loop converges. Inert otherwise. |
6 | 10 | # |
7 | 11 | # Usage: |
8 | | -# ./install.sh # install for the current user |
9 | | -# CLAUDE_CONFIG_DIR=... ./install.sh |
| 12 | +# ./install.sh # build + install for the current user |
| 13 | +# CLAUDE_CONFIG_DIR=... ./install.sh # custom Claude config dir |
10 | 14 | # |
| 15 | +# Requires: Rust (cargo). No runtime dependencies — the binaries are self-contained. |
11 | 16 | set -euo pipefail |
12 | 17 |
|
13 | 18 | REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
14 | | - |
15 | 19 | CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}" |
16 | 20 | CODEX_DIR="${CODEX_CONFIG_DIR:-$HOME/.codex}" |
17 | 21 |
|
| 22 | +build_runtime() { |
| 23 | + command -v cargo >/dev/null 2>&1 || { |
| 24 | + echo " ERROR: cargo (Rust) is required to build the bean runtime." >&2 |
| 25 | + echo " Install from https://rustup.rs and re-run." >&2 |
| 26 | + exit 1 |
| 27 | + } |
| 28 | + echo " building the Rust runtime (release)..." |
| 29 | + cargo build --release --quiet --manifest-path "$REPO_DIR/rs/Cargo.toml" |
| 30 | + mkdir -p "$REPO_DIR/bin" |
| 31 | + for b in bean-check bean-verify bean-run bean-hook; do |
| 32 | + cp "$REPO_DIR/rs/target/release/$b" "$REPO_DIR/bin/$b" |
| 33 | + done |
| 34 | + echo " binaries -> $REPO_DIR/bin (bean-check, bean-verify, bean-run, bean-hook)" |
| 35 | +} |
| 36 | + |
18 | 37 | install_claude() { |
19 | 38 | mkdir -p "$CLAUDE_DIR/skills" |
20 | 39 | rm -rf "$CLAUDE_DIR/skills/bean" |
21 | 40 | cp -R "$REPO_DIR/skills/bean" "$CLAUDE_DIR/skills/bean" |
22 | | - echo " installed bean -> $CLAUDE_DIR/skills/bean (provides /bean)" |
| 41 | + echo " skill -> $CLAUDE_DIR/skills/bean (provides /bean)" |
| 42 | + # register the native Stop hook (idempotent JSON merge into settings.json) |
| 43 | + "$REPO_DIR/bin/bean-hook" --register "$CLAUDE_DIR" | sed 's/^/ /' |
23 | 44 | } |
24 | 45 |
|
25 | 46 | install_codex() { |
26 | 47 | if [ -d "$CODEX_DIR" ]; then |
27 | 48 | mkdir -p "$CODEX_DIR/skills" |
28 | 49 | rm -rf "$CODEX_DIR/skills/bean" |
29 | 50 | cp -R "$REPO_DIR/skills/bean" "$CODEX_DIR/skills/bean" |
30 | | - echo " installed bean -> $CODEX_DIR/skills/bean" |
| 51 | + echo " skill -> $CODEX_DIR/skills/bean" |
| 52 | + # Codex's Stop hook uses the SAME contract as Claude's; register into hooks.json |
| 53 | + "$REPO_DIR/bin/bean-hook" --register "$CODEX_DIR" hooks.json | sed 's/^/ /' |
31 | 54 | else |
32 | 55 | echo " (Codex config dir $CODEX_DIR not found — skipping Codex install)" |
33 | 56 | fi |
34 | 57 | } |
35 | 58 |
|
36 | 59 | echo "Installing bean..." |
| 60 | +build_runtime |
37 | 61 | install_claude |
38 | 62 | install_codex |
39 | | -echo "Done. Restart your client, then invoke /bean." |
| 63 | +echo "Done. Restart Claude Code. In a project, run /bean; the Stop hook keeps the loop honest." |
0 commit comments