From ab5040039ab4f8eff6678c233f1af426715062dc Mon Sep 17 00:00:00 2001 From: qxbyte <126648675+qxbyte@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:24:08 +0800 Subject: [PATCH] feat(ragkit) 0.1.5: add session-start bootstrap hook (skills active without commands on CodeBuddy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0.1.4 dropped commands + made skills user-invocable. On Claude Code that's enough (it natively discovers plugin skills → /ragkit:* shows). But on CodeBuddy a plugin's skills stay INERT without a session-start bootstrap — no command surfaces and the model won't reach for them (superpowers' porting guide: "the bootstrap is the entire integration; without it the skill files are inert"). superpowers works command-less precisely because it HAS this hook; ragkit lacked it. Adds: hooks/hooks.json (SessionStart), hooks/run-hook.sh (specode's proven python-probe launcher, no uv), scripts/ragkit_hooks.py (injects the bootstrap, mirrors spec_hooks.py). The bootstrap announces the 4 skills AND carries the hard anti-improvisation guardrail (invoke by name; never search the filesystem for skill/script files; never read .ragkit vectors / install numpy / hand-roll retrieval; fail loud on script errors) — directly closing the Record-2 hole. Co-Authored-By: Claude Fable 5 Co-Authored-By: qxbyte <126648675+qxbyte@users.noreply.github.com> --- .claude-plugin/marketplace.json | 2 +- plugins/ragkit/.claude-plugin/plugin.json | 2 +- plugins/ragkit/CHANGELOG.md | 6 +++ plugins/ragkit/hooks/hooks.json | 14 ++++++ plugins/ragkit/hooks/run-hook.sh | 40 +++++++++++++++++ plugins/ragkit/scripts/ragkit_hooks.py | 53 +++++++++++++++++++++++ 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 plugins/ragkit/hooks/hooks.json create mode 100755 plugins/ragkit/hooks/run-hook.sh create mode 100644 plugins/ragkit/scripts/ragkit_hooks.py diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 51006f8..62d7f94 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -58,7 +58,7 @@ { "name": "ragkit", "source": "./plugins/ragkit", - "version": "0.1.4", + "version": "0.1.5", "description": "Standalone knowledge-base RAG plugin (vector/lexical/metadata multi-channel recall).", "category": "database", "homepage": "https://github.com/qxbyte/pluginhub", diff --git a/plugins/ragkit/.claude-plugin/plugin.json b/plugins/ragkit/.claude-plugin/plugin.json index 19bb520..62bb5a6 100644 --- a/plugins/ragkit/.claude-plugin/plugin.json +++ b/plugins/ragkit/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ragkit", - "version": "0.1.4", + "version": "0.1.5", "description": "Standalone knowledge-base RAG: chunk + embed + multi-channel recall (vector/lexical/metadata, RRF-fused) over distill-style knowledge-base/ directories.", "author": { "name": "xueqiang", diff --git a/plugins/ragkit/CHANGELOG.md b/plugins/ragkit/CHANGELOG.md index 0f87f98..9601eb5 100644 --- a/plugins/ragkit/CHANGELOG.md +++ b/plugins/ragkit/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +## 0.1.5 (2026-07-08) — 加 session-start bootstrap hook(无 command 也能在 CodeBuddy 出命令) + +- **新增 `hooks/`(session-start bootstrap)**——这是 superpowers 无 command 却能触发/显示 skill 的关键,ragkit 之前缺这块。0.1.4 去掉 commands 后:**Claude Code 原生发现插件 skill、仍出 `/ragkit:*`;但 CodeBuddy 上没有 bootstrap 的插件 skill 是"死的"**(不出命令、模型也不主动调)——对上 superpowers porting 指南那句"bootstrap 就是整个集成,没有它 skill 文件是死的"。 +- 新增文件:`hooks/hooks.json`(SessionStart)+ `hooks/run-hook.sh`(复用 specode 的纯 Python 探测启动器,不走 uv,已在同环境验证)+ `scripts/ragkit_hooks.py`(注入 bootstrap,镜像 spec_hooks.py 的 emit 格式)。 +- bootstrap 内容:声明四个 skill(query/embed/status/eval)+ **防脱轨硬护栏**——只按名调 skill、绝不在文件系统搜 skill/脚本文件(插件在缓存目录不在项目里)、检索只准调 ragkit 脚本、严禁自己读 `.ragkit` 向量/装 numpy/手搓相似度、脚本失败即停报错。直接堵死执行记录-2 那种"绕开插件手搓检索"。 + ## 0.1.4 (2026-07-08) — 去 commands,skill 直接出斜杠(修记录 2 脱轨元凶) - **删掉 `commands/` 目录**(4 个薄壳命令),并从 4 个 skill 去掉 `user-invocable: false`。Claude Code 里 command 已并入 skill——默认(不写 `user-invocable`)的 skill 自动就有 `/ragkit:*` 斜杠入口 + 模型自动调,两样都占。`/ragkit:query` 等入口不变,只是现在**直接由 skill 提供**。 diff --git a/plugins/ragkit/hooks/hooks.json b/plugins/ragkit/hooks/hooks.json new file mode 100644 index 0000000..0bbc0bf --- /dev/null +++ b/plugins/ragkit/hooks/hooks.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "sh \"${CLAUDE_PLUGIN_ROOT:-${CODEBUDDY_PLUGIN_ROOT}}/hooks/run-hook.sh\" \"${CLAUDE_PLUGIN_ROOT:-${CODEBUDDY_PLUGIN_ROOT}}/scripts/ragkit_hooks.py\" session-start" + } + ] + } + ] + } +} diff --git a/plugins/ragkit/hooks/run-hook.sh b/plugins/ragkit/hooks/run-hook.sh new file mode 100755 index 0000000..d62a0d6 --- /dev/null +++ b/plugins/ragkit/hooks/run-hook.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# ragkit plugin python launcher (POSIX / Git Bash / MSYS). +# 依次探测 python3 / python / py,找到就 exec 并透传所有参数。 +# +# Windows 注意:PATH 上的 python.exe / python3.exe 可能是 Microsoft Store 的 +# App Execution Alias stub(路径形如 .../WindowsApps/python3.exe,跑起来只会 +# 打印 "Python was not found" 并 exit 49)。这里通过路径模式跳过这种 stub, +# 继续探测真实解释器(通常落在 py launcher 上)。 + +set -u + +_specode_is_alias_stub() { + case "$1" in + */WindowsApps/python.exe|*/WindowsApps/python3.exe) return 0 ;; + */WindowsApps/python|*/WindowsApps/python3) return 0 ;; + esac + return 1 +} + +p3="$(command -v python3 2>/dev/null || true)" +if [ -n "$p3" ] && ! _specode_is_alias_stub "$p3"; then + exec "$p3" "$@" +fi + +p="$(command -v python 2>/dev/null || true)" +if [ -n "$p" ] && ! _specode_is_alias_stub "$p"; then + exec "$p" "$@" +fi + +if command -v py >/dev/null 2>&1; then + exec py -3 "$@" +fi + +printf '%s\n' "ragkit: 未找到可用的 Python 解释器(已尝试 python3 / python / py)。" >&2 +printf '%s\n' " 请安装 Python 3.8+ 并确保其位于 PATH 中后再次重试。" >&2 +printf '%s\n' " Windows 用户:若提示 \"Python was not found\",多半是命中了 Microsoft" >&2 +printf '%s\n' " Store 的 python.exe 别名 stub。请从 python.org 安装真 Python,或在" >&2 +printf '%s\n' " 「设置 > 应用 > 高级应用设置 > 应用执行别名」中关闭 python.exe /" >&2 +printf '%s\n' " python3.exe 的 Microsoft Store 别名。" >&2 +exit 127 diff --git a/plugins/ragkit/scripts/ragkit_hooks.py b/plugins/ragkit/scripts/ragkit_hooks.py new file mode 100644 index 0000000..695c109 --- /dev/null +++ b/plugins/ragkit/scripts/ragkit_hooks.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""ragkit_hooks.py — RagKit's only hook: SessionStart bootstrap injection. + +Reads stdin (tolerates non-TTY / empty), emits an additionalContext JSON to +stdout, exit 0. Swallows any exception and exits 0 (advisory, never blocks). + +Why this exists: on harnesses like CodeBuddy a plugin's skills stay INERT +without a session-start bootstrap — they don't surface as commands and the +model won't reach for them (superpowers' porting guide: "the bootstrap is the +entire integration; without it the skill files are inert"). Claude Code +natively discovers plugin skills, so RagKit worked there without a hook; other +harnesses need this. Mirrors specode's spec_hooks.py emit shape (proven on the +same setup). The bootstrap also carries the hard guardrail that stops a weak +model from bypassing the plugin and hand-rolling retrieval. +""" +from __future__ import annotations + +import json +import sys + +BOOTSTRAP = ( + "RagKit 可用:对项目 `knowledge-base/` 做多路检索(向量+词汇+元数据,RRF 融合)。" + "四个 skill —— `ragkit:query`(检索,返回定位卡片)/ `ragkit:embed`(构建/更新向量索引)" + "/ `ragkit:status`(索引健康)/ `ragkit:eval`(检索精度评估)。用户要检索 / 建索引 / 查健康时," + "用 `Skill` 工具**按名调用**对应 skill(`/ragkit:*` 或直接按名,无需去找命令文件)。" + "硬约束(防脱轨):① 只按名调 skill,**绝不在文件系统里搜 skill / 脚本文件**——" + "插件文件在插件缓存目录、不在你的项目里,skill 内部会自己定位脚本;" + "② 检索**只能**调 RagKit 的脚本,**严禁**自己读 `.ragkit` 向量文件、装 numpy、" + "或用 embedding API 手搓相似度(结果会错且不可复现);" + "③ 脚本定位 / 运行失败 → 停下报确切错误,不要绕过、不要自己实现。" +) + + +def main() -> int: + try: + try: + sys.stdin.read() + except Exception: + pass + out = { + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": BOOTSTRAP, + } + } + sys.stdout.write(json.dumps(out, ensure_ascii=False)) + except Exception: + pass + return 0 + + +if __name__ == "__main__": + sys.exit(main())