diff --git a/README.md b/README.md index 8729a22..acbb534 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ OpenClaw / Kimi from the same source-of-truth. **Apache 2.0** — explicit patent grant + retaliation clause. 105 Rust crates [REAL: `grep -E '^\s*"[a-z-]+",' _primitives/_rust/Cargo.toml | wc -l`], -68 skills [REAL: `ls skills/ | wc -l`], 38 hooks -[REAL: `grep -c '"command":' settings-snippet.json`], 38 agent manifests +68 skills [REAL: `ls skills/ | wc -l`], 54 hooks +[REAL: `ls hooks/*.sh | wc -l`], 38 agent manifests [REAL: `ls _manifests/*.toml | wc -l`], 85 substrate blocks [REAL: `find _blocks/ -name '*.md' | wc -l`], 18 capability atoms [REAL: `find _capabilities/ -mindepth 2 -maxdepth 2 -type d | wc -l`], @@ -83,7 +83,7 @@ The web installer (`web-install.sh` in this repo, served at repo and delegates to `bootstrap.sh` — single source of truth, no duplicated install logic. -38 agents + 68 skills + 38 hooks + nightly consolidation wired in +38 agents + 68 skills + 54 hooks + nightly consolidation wired in ~60 seconds. Twelve install profiles (`outcome-only`, `minimal`, `core`, `frontend`, `ops`, `dev`, `mcp`, `cortex`, `local-mirror`, `dashboard`, `full-hub`, `full`) defined in diff --git a/_primitives/MANIFEST.toml b/_primitives/MANIFEST.toml index 92db711..d616d16 100644 --- a/_primitives/MANIFEST.toml +++ b/_primitives/MANIFEST.toml @@ -34,10 +34,10 @@ buddy = ["kei-buddy", "kei-telegram-webhook", "kei-shared", "kei-chat-store", # previous one — `dashboard` extends `local-mirror`, `full-hub` extends # `dashboard`. Native macOS arm64 (brew + launchd plists). See # `install/lib-dev-hub-*.sh` for the install logic per component. -local-mirror = ["kei-cortex", "cortex-ui", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner"] -dashboard = ["kei-cortex", "cortex-ui", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner", "kei-projects-index", "kei-projects-watcher", "dev-hub-datasette"] -full-hub = ["kei-cortex", "cortex-ui", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner", "kei-projects-index", "kei-projects-watcher", "dev-hub-datasette", "dev-hub-zoekt", "dev-hub-mdbook", "dev-hub-restic", "dev-hub-gdrive-import"] -full = ["tomd", "kei-doctor", "kei-ledger", "kei-migrate", "kei-changelog", "ssh-check", "firewall-diff", "mock-render", "visual-diff", "tokens-sync", "design-scrape", "live-preview", "figma-tokens", "frontend-inspect", "screenshot-decode", "provision-hetzner", "provision-vultr", "harden-base", "metrics-scrape", "log-ship", "kei-ci-lint", "kei-docs-scaffold", "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", "keisei", "kei-agent-runtime", "kei-capability", "kei-provision", "kei-entity-store", "kei-pipe", "kei-cache", "kei-spawn", "kei-replay", "kei-cortex", "cortex-ui", "kei-pet", "kei-shared", "frustration-matrix", "kei-skill-importer", "kei-projects-index", "kei-projects-watcher", "dev-hub-forgejo", "dev-hub-forgejo-runner", "dev-hub-datasette", "dev-hub-zoekt", "dev-hub-mdbook", "dev-hub-restic", "dev-hub-gdrive-import"] +local-mirror = ["kei-cortex", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner"] +dashboard = ["kei-cortex", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner", "kei-projects-index", "kei-projects-watcher", "dev-hub-datasette"] +full-hub = ["kei-cortex", "kei-pet", "kei-shared", "kei-ledger", "kei-memory", "frustration-matrix", "kei-skill-importer", "kei-router", "kei-dna-index", "kei-atom-discovery", "dev-hub-forgejo", "dev-hub-forgejo-runner", "kei-projects-index", "kei-projects-watcher", "dev-hub-datasette", "dev-hub-zoekt", "dev-hub-mdbook", "dev-hub-restic", "dev-hub-gdrive-import"] +full = ["tomd", "kei-doctor", "kei-ledger", "kei-migrate", "kei-changelog", "ssh-check", "firewall-diff", "mock-render", "visual-diff", "tokens-sync", "design-scrape", "live-preview", "figma-tokens", "frontend-inspect", "screenshot-decode", "provision-hetzner", "provision-vultr", "harden-base", "metrics-scrape", "log-ship", "kei-ci-lint", "kei-docs-scaffold", "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", "keisei", "kei-agent-runtime", "kei-capability", "kei-provision", "kei-entity-store", "kei-pipe", "kei-cache", "kei-spawn", "kei-replay", "kei-cortex", "kei-pet", "kei-shared", "frustration-matrix", "kei-skill-importer", "kei-projects-index", "kei-projects-watcher", "dev-hub-forgejo", "dev-hub-forgejo-runner", "dev-hub-datasette", "dev-hub-zoekt", "dev-hub-mdbook", "dev-hub-restic", "dev-hub-gdrive-import"] # --- shell primitives (13) ------------------------------------------------- @@ -357,12 +357,6 @@ crate = "kei-cortex" deps = ["python3 (>=3.9, for whisper_worker.py subprocess)", "pip install -r scripts/requirements.txt", "ffmpeg (on PATH, faster-whisper audio demux)"] desc = "Local HTTP daemon exposing chat/TTS/STT/portrait endpoints — backs cortex-ui browser app" -[primitive.cortex-ui] -kind = "node" -path = "_ts_packages/packages/cortex-ui" -deps = ["node>=18", "pnpm"] -desc = "Svelte 5 + Vite 5 web UI for kei-cortex daemon (chat panel, Live2D pet renderer, portrait uploader)" - [primitive.frustration-matrix] kind = "rust" crate = "frustration-matrix" diff --git a/bin/kei b/bin/kei index 2d6c6bc..b151d19 100755 --- a/bin/kei +++ b/bin/kei @@ -62,12 +62,10 @@ agent_count() { # Profile from .installed marker file profile_name() { - local f="${AGENTS_DIR}/_primitives/.installed" - if [ -f "$f" ]; then - grep -E "^profile" "$f" 2>/dev/null | head -1 | awk -F= '{gsub(/[ "]/,"",$2); print $2}' || echo "?" - else - echo "?" - fi + # install.sh stamps the chosen profile here; .installed only holds primitive + # names (so the old `grep ^profile .installed` always returned "?"). + local f="$HOME/.claude/.kei-profile" + if [ -f "$f" ]; then head -1 "$f"; else echo "?"; fi } # Last Phase B sleep timestamp diff --git a/bootstrap.sh b/bootstrap.sh index dc47e0e..39a464c 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -51,7 +51,11 @@ prompt_profile() { # Interactive iff stdin is a terminal. NOT stdout: web-install.sh tees stdout # to a logfile (pipe), so -t 1 is false even in an interactive curl|bash. # Prompts print to the terminal via tee; the menu reads from stdin. - if [ ! -t 0 ]; then PROFILE="cortex"; return 0; fi + # Non-interactive (CI / piped, no controlling terminal) → minimal: fast, + # no 105-crate compile, can't half-fail. Matches install.sh's own default + # (was "cortex" here → divergent install vs direct install.sh). Opt up with + # --profile=cortex/full-hub. + if [ ! -t 0 ]; then PROFILE="minimal"; return 0; fi cat <<'WIZARD' ╔═══════════════════════════════════════════════════════════════════╗ diff --git a/install.sh b/install.sh index 2522782..b849207 100755 --- a/install.sh +++ b/install.sh @@ -147,6 +147,9 @@ case "$PROFILE" in ;; esac say "profile: $PROFILE" +# Stamp the chosen profile so `kei` splash + tools can show it (bin/kei reads this). +mkdir -p "$HOME_DIR/.claude" 2>/dev/null || true +printf '%s\n' "$PROFILE" > "$HOME_DIR/.claude/.kei-profile" 2>/dev/null || true # --- resolve profile -> primitive list (UNCONDITIONAL, SSoT) ------------- # Must run BEFORE any reader of PROFILE_PRIMS: the --no-execute plan block diff --git a/install/lib-dev-hub-forgejo.sh b/install/lib-dev-hub-forgejo.sh index 1cf94ba..127d4b9 100644 --- a/install/lib-dev-hub-forgejo.sh +++ b/install/lib-dev-hub-forgejo.sh @@ -160,6 +160,8 @@ _dhf_bootstrap_admin_user() { # Public — install entry point. Called from install.sh primitives phase. install_dev_hub_forgejo() { say "[dev-hub-forgejo] install starting" + # shellcheck source=./lib-launchd.sh + . "$KIT_DIR/install/lib-launchd.sh" # install_service / detect_brew_prefix (was unsourced → command not found) _dhf_check_brew || return 1 _dhf_brew_install || return 1 _dhf_ensure_data_dir || return 1 diff --git a/install/lib-dev-hub-zoekt.sh b/install/lib-dev-hub-zoekt.sh index 3075c78..b552005 100644 --- a/install/lib-dev-hub-zoekt.sh +++ b/install/lib-dev-hub-zoekt.sh @@ -128,6 +128,8 @@ _dhz_print_banner() { # Public — install entry point. Called from install.sh primitives phase. install_dev_hub_zoekt() { say "[dev-hub-zoekt] install starting" + # shellcheck source=./lib-launchd.sh + . "$KIT_DIR/install/lib-launchd.sh" # install_service / detect_brew_prefix (was unsourced → command not found) _dhz_check_brew || return 1 _dhz_check_go_runtime _dhz_brew_install || return 1 diff --git a/install/lib-hooks.sh b/install/lib-hooks.sh index 98d375b..ce09f8d 100644 --- a/install/lib-hooks.sh +++ b/install/lib-hooks.sh @@ -60,9 +60,9 @@ _jq_merge_hooks() { | reduce ($add.hooks | keys[]) as $phase ($orig; .hooks[$phase] = ( ((.hooks[$phase] // []) + ($add.hooks[$phase] // [])) - # Normalize null/absent matcher → "" (Claude Code /doctor rejects null; - # user's pre-kit hooks often have no matcher field). Before group_by so - # null + "" collapse into one group. + # Normalize null/absent matcher to "" (Claude Code /doctor rejects null; + # pre-kit user hooks often have no matcher field) before group_by so + # null and "" collapse into one group. | map(.matcher //= "") | group_by(.matcher) | map( diff --git a/install/lib-menu.sh b/install/lib-menu.sh index c6a0259..cf7a5df 100644 --- a/install/lib-menu.sh +++ b/install/lib-menu.sh @@ -37,7 +37,7 @@ menu_whiptail_profile() { "ops" "+ 9 infra tools — provision, ssh-check, firewall-diff" OFF \ "dev" "+ 17 dev tools — kei-migrate, kei-memory, deep-sleep" OFF \ "mcp" "+ 10 MCP tools — kei-router, kei-sage, kei-auth, kei-pet" OFF \ - "cortex" "+ 11 cortex stack — kei-cortex daemon + cortex-ui" OFF \ + "cortex" "+ 11 cortex stack — kei-cortex daemon + UI primitives" OFF \ "full" "+ all 62 primitives (~5 min, 380 MB)" OFF \ "local-mirror" "dev hub: cortex + Forgejo + CI runner (+ 13 prims)" OFF \ "dashboard" "local-mirror + projects-index + Datasette (+ 16 prims)" OFF \ diff --git a/scripts/kei-message.sh b/scripts/kei-message.sh index 4e56c5a..f7775dc 100755 --- a/scripts/kei-message.sh +++ b/scripts/kei-message.sh @@ -37,7 +37,13 @@ case "$cmd" in done body="${body# }" [ -n "$body" ] || { echo "usage: kei message send [--to ] " >&2; exit 1; } - id="$(date +%s)$(date +%N 2>/dev/null | cut -c1-6 || printf '000000')" + # Sub-second component: GNU `date +%N` where available; on stock macOS (BSD + # date) %N is unsupported and prints literal "N" → fall back to /dev/urandom. + # Result id = epoch(10) + 6 digits = 16-digit integer, safely < 2^53. + ns="$(date +%N 2>/dev/null)" + case "$ns" in *[!0-9]*|'') ns="$(od -An -N4 -tu4 /dev/urandom 2>/dev/null | tr -dc 0-9)" ;; esac + sub="$(printf '%s000000' "$ns" | cut -c1-6)" + id="$(date +%s)${sub}" jq -cn --argjson id "$id" --arg ts "$(date -u +%FT%TZ)" \ --arg from "$me" --arg to "$to" --arg body "$body" \ '{id:$id, ts:$ts, from:$from, to:$to, body:$body}' >> "$LOG" diff --git a/web-install.sh b/web-install.sh index e9d3ec7..a602e65 100755 --- a/web-install.sh +++ b/web-install.sh @@ -78,6 +78,13 @@ mkdir -p "$(dirname "$KEISEI_ROOT")" if [ -d "$KEISEI_ROOT/.git" ]; then say "pulling $KEISEI_REF in $KEISEI_ROOT" git -C "$KEISEI_ROOT" fetch --depth=1 origin "$KEISEI_REF" + # reset --hard discards ANY local edits in this managed clone. It's a managed + # dir (don't hand-edit it — change the repo + push instead), but warn loudly + # so a manual tweak isn't lost silently. + if ! git -C "$KEISEI_ROOT" diff --quiet 2>/dev/null \ + || ! git -C "$KEISEI_ROOT" diff --cached --quiet 2>/dev/null; then + say " ⚠ local changes in $KEISEI_ROOT will be DISCARDED by reset --hard" + fi git -C "$KEISEI_ROOT" reset --hard "origin/$KEISEI_REF" else say "cloning $KEISEI_REPO ($KEISEI_REF) → $KEISEI_ROOT"