diff --git a/README.md b/README.md index 50a1e9c..d541466 100644 --- a/README.md +++ b/README.md @@ -306,10 +306,11 @@ Local installs run as your current user — no root, no service user, no chown. The default chat bridge for OpenCode. On VPS, wp-coding-agents installs post-upgrade hooks that: -- **Remove unwanted bundled skills** — Kimaki ships with skills for frameworks and tools that aren't relevant to WordPress agent workflows. The kill list (`bridges/kimaki/skills-kill-list.txt`) controls which skills are removed after each upgrade. +- **Enable only wp-coding-agents skills** — Kimaki starts with native `--enable-skill` flags for `upgrade-wp-coding-agents` and `wp-coding-agents-setup`, so bundled skills stay on disk but are hidden from the model by Kimaki's skill permissions. +- **Restore custom skills after npm upgrades** — Kimaki still loads skills from its package skills directory, so `post-upgrade.sh` re-copies wp-coding-agents' two custom skill directories from durable config after package updates. - **Filter redundant context** — A plugin strips Kimaki's built-in memory injection and scheduling instructions from the agent context, since DM handles those concerns. Saves ~2,400 tokens per session. -To customize the kill list, edit `bridges/kimaki/skills-kill-list.txt` before running setup, or edit `/opt/kimaki-config/skills-kill-list.txt` on the server after install. +To change the skill allow-list, edit the Kimaki `--enable-skill` arguments rendered by `bridges/kimaki.sh` before running setup or upgrade. On local installs, Kimaki installs globally via npm but without a systemd service. Run it manually: diff --git a/bridges/kimaki.sh b/bridges/kimaki.sh index 5d05501..910f6d5 100644 --- a/bridges/kimaki.sh +++ b/bridges/kimaki.sh @@ -2,18 +2,18 @@ # bridges/kimaki.sh — Kimaki Discord bridge. # # Owns install (local launchd / VPS systemd / Linux-local manual), upgrade-time -# config sync (plugins, post-upgrade.sh, skills kill-list, regression test), -# systemd + launchd template rendering, summary blocks, and the per-bridge -# assets at bridges/kimaki/ (plugins/, post-upgrade.sh, skills-kill-list.txt). +# config sync (plugins, post-upgrade.sh, regression test), systemd + launchd +# template rendering, summary blocks, and the per-bridge assets at +# bridges/kimaki/ (plugins/, post-upgrade.sh). # # Install layout: -# VPS: /opt/kimaki-config/{plugins,post-upgrade.sh,skills-kill-list.txt} +# VPS: /opt/kimaki-config/{plugins,post-upgrade.sh} # + /usr/local/bin/datamachine-kimaki-session # + /usr/local/bin/datamachine-kimaki # + /etc/systemd/system/kimaki.service (ExecStartPre runs post-upgrade.sh) -# Local: $KIMAKI_DATA_DIR/kimaki-config/ for plugins, post-upgrade.sh + -# kill list (executed inline at upgrade time — no launchd -# ExecStartPre hook). opencode.json loads plugins directly from this +# Local: $KIMAKI_DATA_DIR/kimaki-config/ for plugins and post-upgrade.sh +# (executed inline at upgrade time — no launchd ExecStartPre hook). +# opencode.json loads plugins directly from this # durable data-dir copy because `npm update -g kimaki` wipes package- # local files. # + $HOME/.local/bin/datamachine-kimaki-session @@ -30,6 +30,25 @@ bridge_binaries() { echo "kimaki"; } bridge_display_name() { echo "kimaki"; } bridge_display_title() { echo "Kimaki"; } +KIMAKI_ENABLED_SKILLS=(upgrade-wp-coding-agents wp-coding-agents-setup) + +_kimaki_skill_filter_args() { + local skill + for skill in "${KIMAKI_ENABLED_SKILLS[@]}"; do + printf ' --enable-skill %s' "$skill" + done +} + +_kimaki_launchd_skill_filter_args() { + local skill + for skill in "${KIMAKI_ENABLED_SKILLS[@]}"; do + cat <--enable-skill + $skill +EOF + done +} + bridge_is_ready() { [ -n "${KIMAKI_BOT_TOKEN:-}" ] } @@ -247,7 +266,7 @@ bridge_sync_config() { # Resolve paths per environment. # VPS: plugins live at /opt/kimaki-config/plugins (referenced by opencode.json, # and by ExecStartPre in kimaki.service). Config dir holds plugins + - # post-upgrade.sh + skills-kill-list.txt. + # post-upgrade.sh. # Local: opencode.json points at $KIMAKI_DATA_DIR/kimaki-config/plugins, the # durable source that survives `npm update -g kimaki`. Existing configs # that still reference package-local plugin paths are migrated by the @@ -277,8 +296,8 @@ bridge_sync_config() { # setup.sh started creating it). We're in the kimaki dispatch branch, so # kimaki IS the detected bridge and kimaki.service IS running — the # config dir just never got bootstrapped. Create it now from the repo. - # All contents are wp-coding-agents-owned (plugins, post-upgrade.sh, - # kill list); there is no user state to preserve. + # All contents are wp-coding-agents-owned (plugins, post-upgrade.sh); there is + # no user state to preserve. if [ "$LOCAL_MODE" = false ] && [ ! -d "$KIMAKI_CONFIG_DIR" ]; then if [ "$DRY_RUN" = true ]; then echo -e "${BLUE}[dry-run]${NC} Would bootstrap $KIMAKI_CONFIG_DIR from $SCRIPT_DIR/bridges/kimaki/" @@ -286,8 +305,8 @@ bridge_sync_config() { log " $KIMAKI_CONFIG_DIR missing — bootstrapping from repo (install predates v0.4.0)" mkdir -p "$KIMAKI_CONFIG_DIR/plugins" UPDATED_ITEMS+=("bootstrapped $KIMAKI_CONFIG_DIR (install predates v0.4.0)") - # Fall through — the plugin/post-upgrade/kill-list copy logic below - # handles the actual file placement idempotently. + # Fall through — the plugin/post-upgrade copy logic below handles the + # actual file placement idempotently. fi fi @@ -327,7 +346,7 @@ bridge_sync_config() { done fi - # Stage post-upgrade.sh and skills-kill-list.txt in KIMAKI_CONFIG_DIR. + # Stage post-upgrade.sh in KIMAKI_CONFIG_DIR. # On VPS this is read by ExecStartPre. On local we execute it inline below. if [ "$DRY_RUN" = false ]; then mkdir -p "$KIMAKI_CONFIG_DIR" 2>/dev/null || true @@ -348,33 +367,20 @@ bridge_sync_config() { fi fi - if [ -f "$SCRIPT_DIR/bridges/kimaki/skills-kill-list.txt" ]; then - if [ "$DRY_RUN" = true ]; then - if ! cmp -s "$SCRIPT_DIR/bridges/kimaki/skills-kill-list.txt" "$KIMAKI_CONFIG_DIR/skills-kill-list.txt" 2>/dev/null; then - echo -e "${BLUE}[dry-run]${NC} Would update $KIMAKI_CONFIG_DIR/skills-kill-list.txt" - fi - else - if ! cmp -s "$SCRIPT_DIR/bridges/kimaki/skills-kill-list.txt" "$KIMAKI_CONFIG_DIR/skills-kill-list.txt" 2>/dev/null; then - cp "$SCRIPT_DIR/bridges/kimaki/skills-kill-list.txt" "$KIMAKI_CONFIG_DIR/skills-kill-list.txt" - log " Updated $KIMAKI_CONFIG_DIR/skills-kill-list.txt" - UPDATED_ITEMS+=("kimaki-config/skills-kill-list.txt") - fi - fi - fi - # Install wp-coding-agents' Kimaki bridge helpers. They are intentionally # outside Kimaki's npm package so `npm update -g kimaki` cannot wipe them. _kimaki_sync_bin_helpers - # On local, execute post-upgrade.sh inline to enforce the kill list. + # On local, execute post-upgrade.sh inline to refresh package-local custom + # skills and validate plugin state. # On VPS, kimaki.service ExecStartPre runs it on next service restart. if [ "$LOCAL_MODE" = true ] && [ -x "$KIMAKI_CONFIG_DIR/post-upgrade.sh" ]; then if [ "$DRY_RUN" = true ]; then echo -e "${BLUE}[dry-run]${NC} Would run: $KIMAKI_CONFIG_DIR/post-upgrade.sh" else - log " Running post-upgrade.sh to enforce skills kill list..." + log " Running post-upgrade.sh to refresh Kimaki config..." if "$KIMAKI_CONFIG_DIR/post-upgrade.sh" 2>&1 | sed 's/^/ /'; then - UPDATED_ITEMS+=("ran post-upgrade.sh (enforced skills kill list)") + UPDATED_ITEMS+=("ran post-upgrade.sh (refreshed Kimaki config)") else warn " post-upgrade.sh exited non-zero — review output above" fi @@ -547,7 +553,7 @@ $env_block # tolerate exit code 1 (no matches found, the happy path on a clean box). ExecStartPre=-/usr/bin/pkill -TERM -u $SERVICE_USER -f "opencode-ai/bin/.*serve" ExecStartPre=$KIMAKI_CONFIG_DIR/post-upgrade.sh -ExecStart=$KIMAKI_BIN --data-dir $KIMAKI_DATA_DIR --auto-restart --no-critique +ExecStart=$KIMAKI_BIN --data-dir $KIMAKI_DATA_DIR --auto-restart --no-critique$(_kimaki_skill_filter_args) Restart=always RestartSec=10 @@ -577,6 +583,7 @@ bridge_render_launchd() { $KIMAKI_DATA_DIR --auto-restart --no-critique +$(_kimaki_launchd_skill_filter_args) WorkingDirectory $SITE_PATH diff --git a/bridges/kimaki/post-upgrade.sh b/bridges/kimaki/post-upgrade.sh index 071ffb9..345ae5f 100755 --- a/bridges/kimaki/post-upgrade.sh +++ b/bridges/kimaki/post-upgrade.sh @@ -1,13 +1,11 @@ #!/usr/bin/env bash -# post-upgrade.sh — Enforce kimaki skill state and validate plugin state. +# post-upgrade.sh — Restore wp-coding-agents skills and validate plugin state. # -# Three passes run against the npm-installed kimaki package and persistent +# Two passes run against the npm-installed kimaki package and persistent # kimaki-config directory: -# 1. KILL — remove unwanted bundled kimaki skills listed in -# skills-kill-list.txt (target: $(npm root -g)/kimaki/skills/). -# 2. RESTORE skills — re-copy wp-coding-agents skills from the persistent +# 1. RESTORE skills — re-copy wp-coding-agents skills from the persistent # source dir (kimaki-config/skills/) into kimaki/skills/. -# 3. VERIFY plugins — confirm required wp-coding-agents opencode plugins +# 2. VERIFY plugins — confirm required wp-coding-agents opencode plugins # exist at the persistent kimaki-config/plugins path loaded by # opencode.json. Local installs no longer restore plugins into # $(npm root -g)/kimaki/plugins because package-local files are @@ -61,7 +59,6 @@ else SKILLS_DIR="/usr/lib/node_modules/kimaki/skills" fi -KILL_LIST="$(dirname "$0")/skills-kill-list.txt" REQUIRED_PLUGINS=(dm-context-filter.ts dm-agent-sync.ts) WP_CODING_AGENTS_SKILLS=(upgrade-wp-coding-agents wp-coding-agents-setup) @@ -76,46 +73,12 @@ is_wp_coding_agents_skill() { return 1 } -is_killed_skill() { - local candidate="$1" - - [[ -f "$KILL_LIST" ]] || return 1 - - while IFS= read -r skill || [[ -n "$skill" ]]; do - [[ -z "$skill" || "$skill" == \#* ]] && continue - [[ "$candidate" == "$skill" ]] && return 0 - done < "$KILL_LIST" - - return 1 -} - # ---------------------------------------------------------------------------- -# Pass 1: KILL — remove blacklisted bundled kimaki skills. -# ---------------------------------------------------------------------------- - -removed=0 -if [[ ! -d "$SKILLS_DIR" ]]; then - echo "kimaki-config: skills dir not found at $SKILLS_DIR, skipping kill pass" -elif [[ ! -f "$KILL_LIST" ]]; then - echo "kimaki-config: kill list not found at $KILL_LIST, skipping kill pass" -else - while IFS= read -r skill || [[ -n "$skill" ]]; do - # Skip comments and blank lines - [[ -z "$skill" || "$skill" == \#* ]] && continue - target="$SKILLS_DIR/$skill" - if [[ -d "$target" ]]; then - rm -rf "$target" - echo "kimaki-config: removed skill $skill" - removed=$((removed + 1)) - fi - done < "$KILL_LIST" -fi - -# ---------------------------------------------------------------------------- -# Pass 2: RESTORE skills — re-copy wp-coding-agents skills from the +# Pass 1: RESTORE skills — re-copy wp-coding-agents skills from the # persistent source dir into the npm-managed skills dir. Idempotent: `rm -rf` # before each `cp -r` so a stale copy always gets replaced by the current -# source. +# source. Kimaki 0.13 native --enable-skill flags hide non-allowlisted bundled +# skills at runtime, so this script no longer deletes package-owned skill dirs. # ---------------------------------------------------------------------------- if [[ -n "${KIMAKI_SKILL_SOURCE_DIR:-}" ]]; then @@ -135,10 +98,6 @@ elif [[ -d "$SKILL_SOURCE_DIR" ]]; then for skill_dir in "$SKILL_SOURCE_DIR"/*/; do [[ -d "$skill_dir" ]] || continue skill_name="$(basename "$skill_dir")" - if is_killed_skill "$skill_name"; then - echo "kimaki-config: skipped killed skill $skill_name" - continue - fi if ! is_wp_coding_agents_skill "$skill_name"; then echo "kimaki-config: skipped unmanaged skill $skill_name" continue @@ -156,7 +115,7 @@ else fi # ---------------------------------------------------------------------------- -# Pass 3: VERIFY plugins — opencode.json now loads wp-coding-agents plugins +# Pass 2: VERIFY plugins — opencode.json now loads wp-coding-agents plugins # directly from persistent kimaki-config/plugins. When the target and source are # the same directory (the default), there is nothing to restore. An explicit # KIMAKI_PLUGINS_DIR override still receives a best-effort copy for operator @@ -219,4 +178,4 @@ else done fi -echo "kimaki-config: done ($removed skills removed, $skills_restored skills restored, $plugins_restored plugins restored, $missing_required_plugins required plugins missing)" +echo "kimaki-config: done ($skills_restored skills restored, $plugins_restored plugins restored, $missing_required_plugins required plugins missing)" diff --git a/bridges/kimaki/skills-kill-list.txt b/bridges/kimaki/skills-kill-list.txt deleted file mode 100644 index dbf7a93..0000000 --- a/bridges/kimaki/skills-kill-list.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Skills to remove from Kimaki after upgrades. -# One skill directory name per line. Lines starting with # are ignored. - -batch -egaki -errore -event-sourcing-state -gitchamber -goke -jitter -lintcn -npm-package -playwriter -proxyman -spiceflow -termcast -tuistory -usecomputer -x-articles -zele -zustand-centralized-state diff --git a/docs/changelog.md b/docs/changelog.md index 569b1df..064ff98 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Changed +- Kimaki services now use native `--enable-skill` filtering for the wp-coding-agents skills instead of deleting bundled skill directories after npm upgrades (#139). +- `bridges/kimaki/post-upgrade.sh` still restores wp-coding-agents custom skills into Kimaki's package skills path, but no longer prunes arbitrary bundled skills. + ## [1.1.0] - 2026-05-17 ### Added diff --git a/tests/__snapshots__/bridges/kimaki-launchd b/tests/__snapshots__/bridges/kimaki-launchd index 1ce6b3a..c24348f 100644 --- a/tests/__snapshots__/bridges/kimaki-launchd +++ b/tests/__snapshots__/bridges/kimaki-launchd @@ -11,6 +11,10 @@ /home/chubes/.kimaki --auto-restart --no-critique + --enable-skill + upgrade-wp-coding-agents + --enable-skill + wp-coding-agents-setup WorkingDirectory /var/www/site diff --git a/tests/__snapshots__/bridges/kimaki-systemd b/tests/__snapshots__/bridges/kimaki-systemd index d8e44c8..4325d01 100644 --- a/tests/__snapshots__/bridges/kimaki-systemd +++ b/tests/__snapshots__/bridges/kimaki-systemd @@ -22,7 +22,7 @@ Environment=DATAMACHINE_SITE_PATH=/var/www/site # tolerate exit code 1 (no matches found, the happy path on a clean box). ExecStartPre=-/usr/bin/pkill -TERM -u chubes -f "opencode-ai/bin/.*serve" ExecStartPre=/opt/kimaki-config/post-upgrade.sh -ExecStart=/usr/bin/kimaki --data-dir /home/chubes/.kimaki --auto-restart --no-critique +ExecStart=/usr/bin/kimaki --data-dir /home/chubes/.kimaki --auto-restart --no-critique --enable-skill upgrade-wp-coding-agents --enable-skill wp-coding-agents-setup Restart=always RestartSec=10 diff --git a/tests/post-upgrade-restore.sh b/tests/post-upgrade-restore.sh index 8e1ec6f..bb5b911 100755 --- a/tests/post-upgrade-restore.sh +++ b/tests/post-upgrade-restore.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash # tests/post-upgrade-restore.sh — smoke test for bridges/kimaki/post-upgrade.sh # -# Verifies the three passes (kill, restore skills, verify plugins) using -# temp-dir env overrides so the test never touches the real npm install or -# user config. +# Verifies the restore-skill and verify-plugin passes using temp-dir env +# overrides so the test never touches the real npm install or user config. # # What we cover: -# 1. Kill pass removes a blacklisted skill from the simulated skills dir. -# 2. Skill restore pass copies wp-coding-agents SKILL.md trees from the +# 1. Skill restore pass copies wp-coding-agents SKILL.md trees from the # persistent source back into the (wiped) skills dir. +# 2. Native Kimaki --enable-skill filtering replaces the old directory +# deletion workaround, so bundled skills in the package dir are left alone. # 3. Default plugin pass is a no-op because opencode loads the persistent # source dir directly. # 4. Explicit KIMAKI_PLUGINS_DIR compatibility override still copies *.ts @@ -49,7 +49,9 @@ mkdir -p "$LIVE_SKILLS" "$SRC_SKILLS" "$SRC_PLUGINS" # Note: deliberately NOT creating LIVE_PLUGINS — explicit override mode must # still mkdir it. -# Seed a blacklisted skill that the kill pass should remove. +# Seed package-owned skills that post-upgrade must leave alone. Native Kimaki +# --enable-skill flags now hide bundled skills at runtime instead of deleting +# package directories. mkdir -p "$LIVE_SKILLS/blacklisted-skill" echo "stub" > "$LIVE_SKILLS/blacklisted-skill/SKILL.md" mkdir -p "$LIVE_SKILLS/persisted-blacklisted-skill" @@ -94,17 +96,12 @@ cat > "$SRC_PLUGINS/dm-agent-sync.ts" <<'EOF' export default async () => ({}) EOF -# Build a temp skills-kill-list.txt next to a copied post-upgrade.sh so the -# script's `dirname "$0"` lookup finds it. +# Copy post-upgrade.sh into a temp directory so the test executes the same way +# systemd/local upgrade hooks do without touching the real install. TEST_SCRIPT_DIR="$TMP/kimaki-config-dir" mkdir -p "$TEST_SCRIPT_DIR" cp "$POST_UPGRADE" "$TEST_SCRIPT_DIR/post-upgrade.sh" chmod +x "$TEST_SCRIPT_DIR/post-upgrade.sh" -cat > "$TEST_SCRIPT_DIR/skills-kill-list.txt" <<'EOF' -# test kill list -blacklisted-skill -persisted-blacklisted-skill -EOF # Run the script with explicit env overrides so it never touches the real # npm install or user config. @@ -147,12 +144,15 @@ assert_log_contains_file() { fi } -# Pass 1: kill pass removed the blacklisted skill. -assert_missing "$LIVE_SKILLS/blacklisted-skill" -assert_log_contains "removed skill blacklisted-skill" -assert_missing "$LIVE_SKILLS/persisted-blacklisted-skill" -assert_log_contains "removed skill persisted-blacklisted-skill" -assert_log_contains "skipped killed skill persisted-blacklisted-skill" +# Native skill filtering replaced directory pruning, so package-owned bundled +# skills remain on disk. +assert_present "$LIVE_SKILLS/blacklisted-skill/SKILL.md" +assert_present "$LIVE_SKILLS/persisted-blacklisted-skill/SKILL.md" +if grep -q "removed skill" "$TMP/run1.log"; then + echo "FAIL: post-upgrade should not remove skill directories" + cat "$TMP/run1.log" + exit 1 +fi # Pass 2: skill restore copied the allowed SKILL.md tree and skipped unmanaged skills. assert_present "$LIVE_SKILLS/upgrade-wp-coding-agents/SKILL.md" diff --git a/upgrade.sh b/upgrade.sh index 3d20681..9185d82 100755 --- a/upgrade.sh +++ b/upgrade.sh @@ -9,10 +9,9 @@ # 2. Update setup-installed Data Machine plugins to latest tagged releases. # 3. Sync chat-bridge config (dispatches per bridge) # kimaki: -# VPS: /opt/kimaki-config (plugins + post-upgrade.sh + kill list) -# Local: $KIMAKI_DATA_DIR/kimaki-config/ for plugins, -# post-upgrade.sh + kill -# list, and runs post-upgrade.sh inline (no launchd +# VPS: /opt/kimaki-config (plugins + post-upgrade.sh) +# Local: $KIMAKI_DATA_DIR/kimaki-config/ for plugins and +# post-upgrade.sh, and runs post-upgrade.sh inline (no launchd # ExecStartPre hook). # cc-connect: no per-install artifacts; reports binary version and # reminds user to `npm update -g cc-connect`. @@ -328,7 +327,7 @@ update_data_machine_plugins() { # ============================================================================ # Phase 3: Sync chat-bridge config -# kimaki → plugins + post-upgrade.sh + skills-kill-list (see below). +# kimaki → plugins + post-upgrade.sh (see below). # cc-connect → no per-install artifacts beyond the npm package; config.toml # is user-owned. Report version and remind user to # `npm update -g cc-connect` for upstream updates.