From 305787fae314ec630b8c7633564749595ab707e6 Mon Sep 17 00:00:00 2001 From: denis Date: Wed, 20 May 2026 18:50:09 +0000 Subject: [PATCH] fix(install): make fresh install complete + ship tamagotchi (#1) --- .claude-plugin/marketplace.json | 10 +- .claude-plugin/plugin.json | 12 +- HERMES-MIGRATION-PLAN.md | 2 +- PLUGIN.md | 6 +- README.md | 2 +- SECURITY.md | 2 +- _manifests/fal-ai-runner.toml | 4 - _manifests/infra-implementer-cicd.toml | 2 +- _primitives/_rust/Cargo.toml | 4 +- _roles/auditor.toml | 9 -- _roles/merger.toml | 9 -- _ts_packages/packages/mcp-server/package.json | 2 +- bootstrap.sh | 4 +- docs/HANDOFF-WAKE.md | 2 +- docs/INSTALL.md | 2 +- docs/USB-BRAIN-GUIDE-linux.md | 2 +- docs/USB-BRAIN-GUIDE-macos.md | 2 +- docs/USB-BRAIN-GUIDE-windows.md | 2 +- install.sh | 20 +++ install/lib-agents.sh | 10 +- install/lib-args.sh | 2 +- install/lib-hooks.sh | 7 + install/lib-prereqs.sh | 32 ++++- install/lib-rust-prebuild.sh | 4 +- install/lib-scaffold.sh | 21 ++- scripts/keisei-pet-update.sh | 126 ++++++++++++++++++ scripts/keisei-pet.sh | 67 ++++++++++ settings-snippet.json | 23 +++- 28 files changed, 330 insertions(+), 60 deletions(-) create mode 100644 scripts/keisei-pet-update.sh create mode 100644 scripts/keisei-pet.sh diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 734f03a..2cd689d 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,21 +1,21 @@ { "name": "keisei-marketplace", "owner": { - "name": "KeiSei84", - "url": "https://github.com/KeiSei84" + "name": "Denis Parfionovich", + "url": "https://github.com/KeiSeiLab" }, "metadata": { "description": "KeiSei Constructor-Pattern kits and primitives for Claude Code", - "version": "0.16.0" + "version": "0.38.0" }, "plugins": [ { "name": "keisei", "source": { "source": "github", - "repo": "KeiSei84/KeiSeiKit" + "repo": "KeiSeiLab/KeiSeiKit-1.0" }, - "description": "Full KeiSeiKit — 38 agent manifests, 68 skills, 38 hooks, 105 Rust workspace crates (47 installable primitives via MANIFEST.toml `full` profile + 14 shell primitives), sleep-sync cloud consolidation, MCP server layer" + "description": "Full KeiSeiKit — agent manifests, skills, hooks, Rust workspace primitives via MANIFEST.toml profiles (classic ./install.sh), sleep-sync cloud consolidation, MCP server layer" } ] } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 1247475..6f4d6cd 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,13 +1,13 @@ { "name": "keisei", - "version": "0.16.0", - "description": "Constructor-Pattern agent kit for Claude Code: 38 agent manifests, 68 portable skills, 38 hooks, 105 Rust workspace crates (47 installable primitives + 14 shell primitives via MANIFEST.toml `full` profile), typed artifact handoff, sleep-sync cloud consolidation, MCP server layer.", + "version": "0.38.0", + "description": "Constructor-Pattern agent substrate for Claude Code: agent manifests, portable skills, hooks, Rust workspace primitives (installable via MANIFEST.toml profiles through classic ./install.sh), typed artifact handoff, sleep-sync cloud consolidation, MCP server layer.", "author": { - "name": "KeiSei", - "url": "https://github.com/KeiSei84" + "name": "Denis Parfionovich", + "url": "https://github.com/KeiSeiLab" }, - "homepage": "https://github.com/KeiSei84/KeiSeiKit", - "repository": "https://github.com/KeiSei84/KeiSeiKit", + "homepage": "https://github.com/KeiSeiLab/KeiSeiKit-1.0", + "repository": "https://github.com/KeiSeiLab/KeiSeiKit-1.0", "license": "Apache-2.0", "keywords": [ "constructor-pattern", diff --git a/HERMES-MIGRATION-PLAN.md b/HERMES-MIGRATION-PLAN.md index 8d3079e..20a08ff 100644 --- a/HERMES-MIGRATION-PLAN.md +++ b/HERMES-MIGRATION-PLAN.md @@ -383,5 +383,5 @@ Per RULE 0.13 (orchestrator branch first), each phase = orchestrator-created bra ## Sources - `/tmp/hermes-research/hermes-agent/` (NousResearch/hermes-agent @ HEAD, 2026-04-28) -- `~/Projects/KeiSeiKit/` (local, public mirror github.com/KeiSei84/KeiSeiKit-1.0) +- `~/Projects/KeiSeiKit/` (local, public mirror github.com/KeiSeiLab/KeiSeiKit-1.0) - 7 parallel Explore agents, 2026-04-28 session. diff --git a/PLUGIN.md b/PLUGIN.md index 4967b61..c612669 100644 --- a/PLUGIN.md +++ b/PLUGIN.md @@ -6,7 +6,7 @@ This document describes the plugin-format install path (v0.16+) and how it relat ```bash # One-time -/plugin marketplace add KeiSei84/KeiSeiKit +/plugin marketplace add KeiSeiLab/KeiSeiKit-1.0 # Install /plugin install keisei@keisei-marketplace ``` @@ -50,7 +50,7 @@ Paths inside `hooks/hooks.json` use `${CLAUDE_PLUGIN_ROOT}` (expanded by Claude **For plugin install:** - Claude Code 2.1+ (check with `claude --version`) -- Network access to `github.com/KeiSei84/KeiSeiKit` on `/plugin marketplace add` +- Network access to `github.com/KeiSeiLab/KeiSeiKit-1.0` on `/plugin marketplace add` **For the MCP server subset:** - `@keisei/mcp-server` available from **keigit.com** @@ -76,7 +76,7 @@ Paths inside `hooks/hooks.json` use `${CLAUDE_PLUGIN_ROOT}` (expanded by Claude ## Feedback & bugs -Open an issue at [github.com/KeiSei84/KeiSeiKit/issues](https://github.com/KeiSei84/KeiSeiKit/issues). A well-formed problem description is already half the solution. +Open an issue at [github.com/KeiSeiLab/KeiSeiKit-1.0/issues](https://github.com/KeiSeiLab/KeiSeiKit-1.0/issues). A well-formed problem description is already half the solution. ## References diff --git a/README.md b/README.md index 2ed45b6..8729a22 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ curl -fsSL https://install.keisei.app | bash curl -fsSL https://install.keisei.app | bash -s -- --profile=dev --yes # CI # Claude Code (primary target — full hook + agent integration) -/plugin marketplace add KeiSei84/KeiSeiKit-1.0 +/plugin marketplace add KeiSeiLab/KeiSeiKit-1.0 /plugin install keisei@keisei-marketplace # Any MCP-compatible client (Cursor / Continue / Zed / Aider / etc) diff --git a/SECURITY.md b/SECURITY.md index 339680f..f468b99 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,7 +12,7 @@ Email `parfionovich@keilab.io` with a description and reproduction steps. PGP ke ## Supported versions -Latest `v0.14.x` tag. Older versions accept fixes for CVEs only. +Latest `v0.38.x` tag. Older versions accept fixes for CVEs only. ## Audit diff --git a/_manifests/fal-ai-runner.toml b/_manifests/fal-ai-runner.toml index a8e1c61..5032029 100644 --- a/_manifests/fal-ai-runner.toml +++ b/_manifests/fal-ai-runner.toml @@ -94,10 +94,6 @@ trigger = "fal.ai call needs to be wired into project source beyond a throwaway target = "validator" trigger = "generated assets include text / citations / claims that need RULE 0.4 verification before shipping" -[[handoff]] -target = "keimd-expert" -trigger = "user asks \"what assets already exist in this project\" — knowledge graph search, not fal.ai call" - [[handoff]] target = "critic" trigger = "anti-pattern sweep after batch — are prompts / generated assets consistent / on-brand?" diff --git a/_manifests/infra-implementer-cicd.toml b/_manifests/infra-implementer-cicd.toml index 46b31f1..6c385cf 100644 --- a/_manifests/infra-implementer-cicd.toml +++ b/_manifests/infra-implementer-cicd.toml @@ -33,7 +33,7 @@ forbidden_domain = [ "IaC (Terraform/Pulumi/CDK) — hand off to infra-implementer-iac", "Dockerfiles or OCI images — hand off to infra-implementer-container", "Secrets management (Vault, sops, age) — hand off to infra-implementer-secrets", - "Hardcoded secrets in workflow YAML (RULE 0.8) — use `${{ secrets.NAME }}` / ENV refs", + "Hardcoded secrets in workflow YAML (RULE 0.8) — use repo/org secret refs + ENV, never inline", "Skipping build-cache steps — always cache cargo registry + target, node_modules, pip cache", ] output_extra_fields = [ diff --git a/_primitives/_rust/Cargo.toml b/_primitives/_rust/Cargo.toml index 3da1ea6..e5c0629 100644 --- a/_primitives/_rust/Cargo.toml +++ b/_primitives/_rust/Cargo.toml @@ -198,8 +198,8 @@ edition = "2021" rust-version = "1.77" authors = ["Denis Parfionovich "] license = "Apache-2.0" -repository = "https://github.com/KeiSei84/KeiSeiKit-1.0" -homepage = "https://github.com/KeiSei84/KeiSeiKit-1.0" +repository = "https://github.com/KeiSeiLab/KeiSeiKit-1.0" +homepage = "https://github.com/KeiSeiLab/KeiSeiKit-1.0" [workspace.dependencies] clap = { version = "4", features = ["derive", "env"] } diff --git a/_roles/auditor.toml b/_roles/auditor.toml index 11dc284..e9736ed 100644 --- a/_roles/auditor.toml +++ b/_roles/auditor.toml @@ -27,15 +27,6 @@ language = "toml" [pipeline] handoff = ["merger"] -[taxonomy] -kingdom = "role" -mechanism = "audit" -domain = "agent" -layer = "agent-substrate" -stage = "runtime" -stability = "stable" -language = "toml" - [lineage] parents = [] creator = "ag-orchestrator-human" diff --git a/_roles/merger.toml b/_roles/merger.toml index 9f24a96..a9b0409 100644 --- a/_roles/merger.toml +++ b/_roles/merger.toml @@ -27,15 +27,6 @@ language = "toml" [pipeline] handoff = [] -[taxonomy] -kingdom = "role" -mechanism = "merge" -domain = "agent" -layer = "agent-substrate" -stage = "runtime" -stability = "stable" -language = "toml" - [lineage] parents = [] creator = "ag-orchestrator-human" diff --git a/_ts_packages/packages/mcp-server/package.json b/_ts_packages/packages/mcp-server/package.json index 7b8e625..b4ce2e1 100644 --- a/_ts_packages/packages/mcp-server/package.json +++ b/_ts_packages/packages/mcp-server/package.json @@ -19,7 +19,7 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/KeiSei84/KeiSeiKit-1.0.git", + "url": "git+https://github.com/KeiSeiLab/KeiSeiKit-1.0.git", "directory": "_ts_packages/packages/mcp-server" }, "publishConfig": { diff --git a/bootstrap.sh b/bootstrap.sh index 6a51ee0..d507da5 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -8,7 +8,7 @@ # # Usage from a fresh machine (private repo, gh CLI required for clone): # gh auth login -# gh repo clone KeiSei84/KeiSeiKit-1.0 +# gh repo clone KeiSeiLab/KeiSeiKit-1.0 # cd KeiSeiKit-1.0 && ./bootstrap.sh # # What it does (idempotent — re-running is safe): @@ -164,7 +164,7 @@ fi KIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ ! -f "$KIT_DIR/install.sh" ]; then err "install.sh not found in $KIT_DIR — am I inside a KeiSeiKit checkout?" - err "if not: gh repo clone KeiSei84/KeiSeiKit-1.0 && cd KeiSeiKit-1.0 && ./bootstrap.sh" + err "if not: gh repo clone KeiSeiLab/KeiSeiKit-1.0 && cd KeiSeiKit-1.0 && ./bootstrap.sh" exit 1 fi log "checkout: $KIT_DIR" diff --git a/docs/HANDOFF-WAKE.md b/docs/HANDOFF-WAKE.md index 4301036..5d032fb 100644 --- a/docs/HANDOFF-WAKE.md +++ b/docs/HANDOFF-WAKE.md @@ -63,7 +63,7 @@ cd _primitives/_rust && cargo test --workspace 2>&1 | tail -5 ## GitHub Releases status -6 tags pushed. Release workflow in `release.yml` triggers on tag push. Expected: 6 releases × (3 Rust tarballs + 5 MCP binaries + sha256 each) = ~48 assets. Check `github.com/KeiSei84/KeiSeiKit/releases` on wake — all tags should have attached assets within 10 min of push per prior v0.22.3 smoke. CI was re-triggered after Pro upgrade; confirm status there. +6 tags pushed. Release workflow in `release.yml` triggers on tag push. Expected: 6 releases × (3 Rust tarballs + 5 MCP binaries + sha256 each) = ~48 assets. Check `github.com/KeiSeiLab/KeiSeiKit-1.0/releases` on wake — all tags should have attached assets within 10 min of push per prior v0.22.3 smoke. CI was re-triggered after Pro upgrade; confirm status there. ## What substrate looks like now diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 6c5b194..549d781 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -8,7 +8,7 @@ Complete install guide. Quick-start lives in the main [README](../README.md#inst | Path | Command | Best for | |---|---|---| -| **Plugin** (v0.16+, recommended on Claude Code 2.1+) | `/plugin marketplace add KeiSei84/KeiSeiKit` then `/plugin install keisei@keisei-marketplace` | Agents + skills + hooks + MCP. Zero cargo build. See [PLUGIN.md](../PLUGIN.md). | +| **Plugin** (v0.16+, recommended on Claude Code 2.1+) | `/plugin marketplace add KeiSeiLab/KeiSeiKit-1.0` then `/plugin install keisei@keisei-marketplace` | Agents + skills + hooks + MCP. Zero cargo build. See [PLUGIN.md](../PLUGIN.md). | | **Classic** `./install.sh` | Below | Full kit incl. 47 Rust primitives + 13 shell primitives. Required for `ops` / `dev` / `full` profiles. | ## Prerequisites diff --git a/docs/USB-BRAIN-GUIDE-linux.md b/docs/USB-BRAIN-GUIDE-linux.md index 51606dc..3fece80 100644 --- a/docs/USB-BRAIN-GUIDE-linux.md +++ b/docs/USB-BRAIN-GUIDE-linux.md @@ -14,7 +14,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests} ## 2. Download MCP server binaries ```bash -BASE=https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0 +BASE=https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0 cd "$BRAIN/bin" for n in darwin-arm64 darwin-x64 linux-x64 linux-arm64 windows-x64.exe; do curl -fL -O "$BASE/kei-mcp-server-$n" 2>/dev/null || echo "skipped $n" diff --git a/docs/USB-BRAIN-GUIDE-macos.md b/docs/USB-BRAIN-GUIDE-macos.md index 6a2a729..ee7522f 100644 --- a/docs/USB-BRAIN-GUIDE-macos.md +++ b/docs/USB-BRAIN-GUIDE-macos.md @@ -12,7 +12,7 @@ mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests} ## 2. Download MCP server binaries ```bash -BASE=https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0 +BASE=https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0 cd "$BRAIN/bin" for n in darwin-arm64 darwin-x64 linux-x64 windows-x64.exe; do curl -fL -O "$BASE/kei-mcp-server-$n" diff --git a/docs/USB-BRAIN-GUIDE-windows.md b/docs/USB-BRAIN-GUIDE-windows.md index b4dcbcf..2efc795 100644 --- a/docs/USB-BRAIN-GUIDE-windows.md +++ b/docs/USB-BRAIN-GUIDE-windows.md @@ -18,7 +18,7 @@ New-Item -ItemType Directory -Path $BRAIN,"$BRAIN\bin","$BRAIN\memory","$BRAIN\a ## 2. Download MCP server binaries ```powershell -$BASE = "https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0" +$BASE = "https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/download/v0.21.0" Push-Location "$BRAIN\bin" $names = @( diff --git a/install.sh b/install.sh index 598ee10..0250fd9 100755 --- a/install.sh +++ b/install.sh @@ -148,6 +148,26 @@ case "$PROFILE" in esac say "profile: $PROFILE" +# --- resolve profile -> primitive list (UNCONDITIONAL, SSoT) ------------- +# Must run BEFORE any reader of PROFILE_PRIMS: the --no-execute plan block +# below, the --skip-prereqs path (which bypasses check_prereqs), and the +# conditional cargo gate in check_hard_prereqs. Previously this lived only +# inside check_prereqs, so --no-execute / --skip-prereqs saw PROFILE_PRIMS +# unbound and silently resolved to 0 primitives. +resolve_profile_prims + +# --- skip heavy substrate workspace build for no-rust-primitive profiles -- +# The agent assembler always compiles (tiny), but the 105-crate substrate +# workspace (kei-fork / kei-ledger / kei-cortex / ...) only matters for +# profiles that ship rust primitives. With no prebuilt release binaries, +# every install would otherwise fall back to a 5-15 min `cargo build +# --workspace`. Auto-skip keeps minimal / shell-only profiles fast. An +# explicit user-set KEI_SKIP_RUST always wins. +if [ -z "${KEI_SKIP_RUST:-}" ] && ! _profile_needs_cargo; then + export KEI_SKIP_RUST=1 + say "no rust primitives in profile=$PROFILE -> skipping substrate workspace build (assembler only)" +fi + # --- welcome banner + onboarding wizard ---------------------------------- # Banner всегда EN — пользователь ещё не выбрал язык. # Wizard: TTY + нет ~/.claude/.onboarded + не задан KEISEI_SKIP_ONBOARD. diff --git a/install/lib-agents.sh b/install/lib-agents.sh index 1c1ca7f..b595aea 100644 --- a/install/lib-agents.sh +++ b/install/lib-agents.sh @@ -98,7 +98,15 @@ build_assembler() { } # Run the built assembler in --in-place mode to write the agent .md files. +# Tolerant by design: a handful of stale/broken manifests (e.g. a handoff to +# an agent not shipped in this profile, or an un-substituted template field) +# must NOT abort the whole install — hooks, skills, settings still need to +# land. The assembler prints per-manifest FAIL lines for visibility, and the +# commit-time assembler-validate gate stays strict, so genuine breakage is +# still caught at authoring time. generate_agents() { say "generating agent .md files (--in-place)" - AGENT_ROOT="$AGENTS_DIR" "$AGENTS_DIR/_assembler/target/release/assemble" --in-place + if ! AGENT_ROOT="$AGENTS_DIR" "$AGENTS_DIR/_assembler/target/release/assemble" --in-place; then + warn "some agent manifests failed to assemble (see FAIL lines above) — continuing install" + fi } diff --git a/install/lib-args.sh b/install/lib-args.sh index 9726982..8fe9ce0 100644 --- a/install/lib-args.sh +++ b/install/lib-args.sh @@ -28,7 +28,7 @@ Usage: ./install.sh [flags] NOTE: this classic installer is for power users (Rust primitives, custom profiles, full control). Most users should prefer the Claude Code plugin: - /plugin marketplace add KeiSei84/KeiSeiKit + /plugin marketplace add KeiSeiLab/KeiSeiKit-1.0 /plugin install keisei@keisei-marketplace See README.md "Plugin install (v0.16+, recommended)" and PLUGIN.md for details. The classic installer and the plugin can coexist — use whichever diff --git a/install/lib-hooks.sh b/install/lib-hooks.sh index c4f33fc..b4fd38a 100644 --- a/install/lib-hooks.sh +++ b/install/lib-hooks.sh @@ -80,6 +80,13 @@ _jq_merge_hooks() { ) ) ) + # statusLine (KeiSei tamagotchi): set ONLY when the target has none. + # Never clobber an existing statusLine. Fresh-install path drops the + # snippet verbatim, so this only matters when merging into a + # pre-existing settings.json. + | if (.statusLine // null) == null and ($add.statusLine // null) != null + then .statusLine = $add.statusLine + else . end ' "$target" > "$tmp" if [ -s "$tmp" ] && jq -e . "$tmp" >/dev/null 2>&1; then mv "$tmp" "$target" diff --git a/install/lib-prereqs.sh b/install/lib-prereqs.sh index 1e87eb7..31ed81a 100644 --- a/install/lib-prereqs.sh +++ b/install/lib-prereqs.sh @@ -9,8 +9,29 @@ # Reads globals: $PROFILE, $CUSTOM_PRIMS, $MANIFEST. # Sets global: $PROFILE_PRIMS (space-separated primitive names). -# Hard checks: cargo + jq. Exit 1 on missing — without them the install -# (or the installed hooks afterwards) cannot function. +# Does the resolved profile contain at least one rust primitive? Only then +# is a functional cargo toolchain a HARD requirement. Profiles like minimal +# (0 primitives) and shell-only customs build nothing and must install +# without Rust — README promises "minimal — NO Rust compile". Requires +# PROFILE_PRIMS already resolved (resolve_profile_prims, called by install.sh +# and at the top of check_prereqs). +_profile_needs_cargo() { + local p kind + for p in ${PROFILE_PRIMS:-}; do + kind="$(primitive_field "$p" kind 2>/dev/null || true)" + [ "$kind" = "rust" ] && return 0 + done + return 1 +} + +# Hard checks: cargo + jq, both always required. +# cargo — the agent assembler (build_assembler) compiles a small rust binary +# to generate the agent .md files on EVERY profile, so cargo is +# non-negotiable. The heavy 105-crate substrate *workspace* build is +# a separate concern: install.sh auto-sets KEI_SKIP_RUST for profiles +# with no rust primitives so minimal stays fast (assembler only). +# jq — the installed hooks parse Claude Code JSON via jq and would abort +# tool calls without it. check_hard_prereqs() { say "checking prerequisites" if ! command -v cargo >/dev/null 2>&1; then @@ -103,9 +124,12 @@ check_soft_prereqs() { fi } -# Top-level orchestrator: hard first (exit on miss), then resolve + soft. +# Top-level orchestrator: resolve profile first (idempotent — install.sh +# already resolved it before the no-execute/skip-prereqs branches), so the +# conditional cargo gate in check_hard_prereqs can see PROFILE_PRIMS; then +# hard checks (exit on miss); then soft warnings. check_prereqs() { - check_hard_prereqs resolve_profile_prims + check_hard_prereqs check_soft_prereqs } diff --git a/install/lib-rust-prebuild.sh b/install/lib-rust-prebuild.sh index ebab772..b7987ac 100644 --- a/install/lib-rust-prebuild.sh +++ b/install/lib-rust-prebuild.sh @@ -11,7 +11,7 @@ # Path A — download from latest github release (fast, no Rust required): # 1. Detect platform via uname → Rust target triple. # 2. Fetch keisei-${TARGET}.tar.gz from -# https://github.com/KeiSei84/KeiSeiKit-1.0/releases/latest/download/ +# https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/latest/download/ # 3. Verify sha256. # 4. Extract into target/release/. # @@ -62,7 +62,7 @@ download_release_tarball() { local target="$1" [ -n "$target" ] || return 1 local tarball="keisei-${target}.tar.gz" - local url="https://github.com/KeiSei84/KeiSeiKit-1.0/releases/latest/download/${tarball}" + local url="https://github.com/KeiSeiLab/KeiSeiKit-1.0/releases/latest/download/${tarball}" local tmp tmp="$(mktemp -d -t keisei-prebuild-XXXX 2>/dev/null)" || return 1 command -v curl >/dev/null 2>&1 || { rm -rf "$tmp"; return 1; } diff --git a/install/lib-scaffold.sh b/install/lib-scaffold.sh index 51870d7..0903c86 100644 --- a/install/lib-scaffold.sh +++ b/install/lib-scaffold.sh @@ -24,7 +24,8 @@ setup_target_dirs() { "$AGENTS_DIR/_generated" \ "$HOOKS_DIR" \ "$SKILLS_DIR/new-agent" \ - "$HOME_DIR/.claude/memory" + "$HOME_DIR/.claude/memory" \ + "$HOME_DIR/.claude/scripts" } # Write a stub MEMORY.md if the user has no index yet. We never overwrite. @@ -65,6 +66,23 @@ copy_sleep_scripts() { fi } +# KeiSei tamagotchi statusline — copy the renderer + state updater into +# ~/.claude/scripts/. Zero binary deps (pure bash, state under ~/.claude/pet/), +# always available regardless of profile. The statusLine + pet-update hooks +# are wired into settings.json by the settings-snippet merge (lib-hooks.sh). +copy_pet_scripts() { + local pet_sh src dst="$HOME_DIR/.claude/scripts" + [ -d "$KIT_DIR/scripts" ] || return 0 + mkdir -p "$dst" + for pet_sh in keisei-pet.sh keisei-pet-update.sh; do + src="$KIT_DIR/scripts/$pet_sh" + if [ -f "$src" ]; then + cp -f "$src" "$dst/$pet_sh" + chmod +x "$dst/$pet_sh" + fi + done +} + # Clean slate: drop every shell .sh + rust crate dir from the installed set. # FAST (no per-rust rebuild). A single regenerate_rust_workspace at the end # of install_primitives handles the final state. @@ -99,6 +117,7 @@ install_profile_primitives() { run_primitives_phase() { copy_primitives_meta copy_sleep_scripts + copy_pet_scripts say "resolving primitives for profile=$PROFILE" clean_slate_primitives install_profile_primitives diff --git a/scripts/keisei-pet-update.sh b/scripts/keisei-pet-update.sh new file mode 100644 index 0000000..3726cff --- /dev/null +++ b/scripts/keisei-pet-update.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# KeiSei pet state updater — called by hooks to change the pet's mood. +# Usage: keisei-pet-update.sh +# Events: prompt | rust_write | github_block | python_no_reason | +# modal_cost | patent_filed | concept_saved | secret_leak | +# test_pass | test_fail | sleep | rule_violation | idle +# +# The hook may also pipe JSON tool-context on stdin; we ignore it for now +# (future: parse tool_input to make reactions smarter). + +set -u + +STATE_DIR="${HOME}/.claude/pet" +STATE="${STATE_DIR}/state" +HISTORY="${STATE_DIR}/history.log" +mkdir -p "$STATE_DIR" + +# Load current state +mood="neutral" +message="" +since=$(date +%s) +rust_today=0 +patents_today=0 +violations=0 + +# shellcheck source=/dev/null +[ -f "$STATE" ] && source "$STATE" 2>/dev/null || true + +# Daily counter reset (if state last updated yesterday) +last_day=${day:-} +today=$(date +%Y-%m-%d) +if [ "$last_day" != "$today" ]; then + rust_today=0 + patents_today=0 + violations=0 +fi + +event="${1:-}" +now=$(date +%s) + +# Discard stdin quickly so hook doesn't block +if [ ! -t 0 ]; then + cat >/dev/null 2>&1 || true +fi + +case "$event" in + prompt) + mood="thinking" + message="考えてる..." + ;; + rust_write) + rust_today=$((rust_today + 1)) + mood="happy" + message="構造式 ✓ Rust" + ;; + github_block) + mood="angry" + message="RULE 0.1! no github" + violations=$((violations + 1)) + ;; + python_no_reason) + mood="alert" + message="Python? 理由は? (RULE 0.2)" + ;; + modal_cost) + mood="alert" + message="\$\$ compute check" + ;; + patent_filed) + mood="proud" + patents_today=$((patents_today + 1)) + message="特許 filed!" + ;; + concept_saved) + mood="happy" + message="💡 concept saved" + ;; + secret_leak) + mood="angry" + message="SECRET! RULE 0.8" + violations=$((violations + 1)) + ;; + test_pass) + mood="happy" + message="テスト ✓" + ;; + test_fail) + mood="sad" + message="テスト ✗" + ;; + rule_violation) + mood="angry" + message="rule violation ⚠" + violations=$((violations + 1)) + ;; + sleep) + mood="sleep" + message="zzz" + ;; + *) + # unknown event — no-op, keep current state + : + ;; +esac + +# Write state atomically +tmp="${STATE}.tmp.$$" +cat > "$tmp" <> "$HISTORY" +if [ -f "$HISTORY" ] && [ "$(wc -l < "$HISTORY")" -gt 50 ]; then + tail -50 "$HISTORY" > "${HISTORY}.tmp" && mv "${HISTORY}.tmp" "$HISTORY" +fi + +# Hooks in Claude Code expect exit 0 to pass through +exit 0 diff --git a/scripts/keisei-pet.sh b/scripts/keisei-pet.sh new file mode 100644 index 0000000..33ffac1 --- /dev/null +++ b/scripts/keisei-pet.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# KeiSei tamagotchi — statusline renderer. +# Called by Claude Code on every prompt render. Outputs ONE line. +# Reads state from ~/.claude/pet/state (written by keisei-pet-update.sh). + +set -u + +# Discard any stdin (Claude Code may pipe session JSON to statusLine) +if [ ! -t 0 ]; then + cat >/dev/null 2>&1 || true +fi + +STATE="${HOME}/.claude/pet/state" + +# Defaults (if state file missing/stale) +mood="neutral" +message="" +since=$(date +%s) +rust_today=0 +patents_today=0 +violations=0 + +# shellcheck source=/dev/null +[ -f "$STATE" ] && source "$STATE" 2>/dev/null || true + +now=$(date +%s) +idle=$((now - since)) + +# Idle >5 min → pet sleeps (unless it's angry/alert about something) +if [ "$idle" -gt 300 ] && [ "$mood" != "angry" ] && [ "$mood" != "alert" ]; then + mood="sleep" + message="zzz" +fi + +# Face + color by mood +case "$mood" in + happy) face="(ᵔᴥᵔ)"; color=$'\033[32m' ;; # green + proud) face="(•̀ᴗ•́)و"; color=$'\033[1;32m';; # bright green + thinking) face="(⊙.⊙)"; color=$'\033[36m' ;; # cyan + alert) face="(ʘᴗʘ)"; color=$'\033[33m' ;; # yellow + angry) face="(ò_ó)"; color=$'\033[31m' ;; # red + sad) face="(╥﹏╥)"; color=$'\033[34m' ;; # blue + sleep) face="(-.-)"; color=$'\033[2;37m';; # dim gray + *) face="(•ᴗ•)"; color=$'\033[37m' ;; # white (neutral) +esac + +dim=$'\033[2m' +reset=$'\033[0m' + +# stats line (compact) +stats="" +[ "$rust_today" -gt 0 ] && stats+=" 🦀${rust_today}" +[ "$patents_today" -gt 0 ] && stats+=" 📜${patents_today}" +[ "$violations" -gt 0 ] && stats+=" ⚠${violations}" + +# Project name from PWD +proj="${PWD##*/}" +[ -z "$proj" ] && proj="~" + +# Render: face | message | stats | project +# Keep it ≤ one line +printf "%s%s%s %s%s%s%s%s %s%s%s" \ + "$color" "$face" "$reset" \ + "$dim" "$message" "$reset" \ + "$stats" \ + "" \ + "$dim" "📁 $proj" "$reset" diff --git a/settings-snippet.json b/settings-snippet.json index ea4e3c9..c0b383e 100644 --- a/settings-snippet.json +++ b/settings-snippet.json @@ -1,5 +1,10 @@ { - "_comment": "Merge these entries into your ~/.claude/settings.json under the matching keys. If you already have PostToolUse/PreToolUse/Stop arrays, append the objects below to them instead of overwriting. install.sh --activate-hooks automates the merge and de-dupes by hooks[].command.", + "_comment": "Merge these entries into your ~/.claude/settings.json under the matching keys. If you already have PostToolUse/PreToolUse/Stop arrays, append the objects below to them instead of overwriting. install.sh --activate-hooks automates the merge and de-dupes by hooks[].command. statusLine (the KeiSei tamagotchi) is set ONLY when you have none — an existing statusLine is never clobbered.", + "statusLine": { + "type": "command", + "command": "~/.claude/scripts/keisei-pet.sh", + "padding": 0 + }, "hooks": { "PostToolUse": [ { @@ -18,6 +23,10 @@ "type": "command", "command": "~/.claude/hooks/post-write-check.sh", "statusMessage": "post-write checks..." + }, + { + "type": "command", + "command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); [ -n \"$FILE\" ] && [ \"${FILE##*.}\" = 'rs' ] && ~/.claude/scripts/keisei-pet-update.sh rust_write; exit 0" } ] }, @@ -113,6 +122,10 @@ "type": "command", "command": "~/.claude/hooks/no-github-push.sh", "statusMessage": "no-github-push guard (RULE 0.1)..." + }, + { + "type": "command", + "command": "CMD=$(cat | jq -r '.tool_input.command // empty'); echo \"$CMD\" | grep -qiE 'git push.*github|gh repo (create|push|sync)' && ~/.claude/scripts/keisei-pet-update.sh github_block; exit 0" } ] }, @@ -207,6 +220,10 @@ "type": "command", "command": "~/.claude/hooks/chat-numeric-prewarn.sh", "statusMessage": "chat-numeric-prewarn (RULE 0.18)..." + }, + { + "type": "command", + "command": "~/.claude/scripts/keisei-pet-update.sh prompt" } ] } @@ -238,6 +255,10 @@ "type": "command", "command": "~/.claude/hooks/chat-numeric-postflag.sh", "statusMessage": "chat-numeric-postflag (RULE 0.18)..." + }, + { + "type": "command", + "command": "~/.claude/scripts/keisei-pet-update.sh sleep" } ] }