Skip to content

feat: add /reload-skills slash command (CLI + Web UI)#1057

Open
jarvis24young wants to merge 1 commit into
GCWing:mainfrom
jarvis24young:feat/reload-skills-command
Open

feat: add /reload-skills slash command (CLI + Web UI)#1057
jarvis24young wants to merge 1 commit into
GCWing:mainfrom
jarvis24young:feat/reload-skills-command

Conversation

@jarvis24young
Copy link
Copy Markdown
Contributor

@jarvis24young jarvis24young commented Jun 3, 2026

对标

Claude Code 2.1.152 changelog:

Added /reload-skills command to re-scan skill directories without restarting the session

这个 PR 做什么

在 BitFun 的 CLI 和 Web UI 同时暴露 /reload-skills 命令,让用户改完 skill 文件后不必重启 BitFun 即可让改动生效。

现状

SkillRegistry::refresh()src/crates/core/src/agentic/tools/implementations/skills/registry.rs:729)和 Tauri RPC get_skill_configs(force_refresh: true)src/apps/desktop/src/api/skill_api.rs:467)以及 configAPI.getSkillConfigs({ forceRefresh: true })src/web-ui/src/infrastructure/api/service-api/ConfigAPI.ts:278全部已就绪——后端+IPC 链路已通。

只缺用户入口。 本 PR 仅加 UI 入口(一个 CommandSpec + 一个 match arm + 一个 action item + 一个 submit 函数 + i18n),0 后端改动。

行为

CLI(/reload-skills

$ /reload-skills
[状态栏] Skills reloaded (12 available)
[系统消息] Reloaded 12 skill(s) from disk.
  • 不需要 is_processing === false 守卫(cheap read,atomic cache swap)
  • 复用 SkillRegistry::global() 直接调用(CLI 跟 desktop 运行时共享同一 registry,不需要走 Tauri bridge)
  • 使用 rt_handle: &tokio::runtime::Handle 参数(与其他 async CLI helper 一致)

Web UI

  1. 聊天输入框输入 / → 命令 picker 多一项 Reload skills
  2. 选中 → 输入框填入 /reload-skills
  3. 按 Enter → 静默 refresh + 成功 toast (Reloaded skills (12 available))
  4. 失败时显示错误 toast (Failed to reload skills)
  5. 输入 /reload-skills foo → 警告 toast Use /reload-skills without extra arguments.

完全复用 /usage/init 的命令路由模式(pick → input → Enter → handleSendOrCancel matcher → submit 函数)。

改动文件

src/apps/cli/src/commands.rs                       (+1 entry in COMMAND_SPECS)
src/apps/cli/src/modes/chat.rs                      (+1 match arm + 1 method)
src/web-ui/src/flow_chat/components/ChatInput.tsx   (+1 picker entry + 1 selectSlashCommandAction
                                                      branch + 1 submitReloadSkillsFromInput
                                                      + 1 handleSendOrCancel matcher
                                                      + 1 handleSendOrCancel startsWith warning
                                                      + 1 deps list entry)
src/web-ui/src/locales/en-US/flow-chat.json          (+4 keys)
src/web-ui/src/locales/zh-CN/flow-chat.json          (+4 keys)
src/web-ui/src/locales/zh-TW/flow-chat.json          (+4 keys)

总计 6 文件,+120 行单 commit fb7996c0,rebase 在最新 origin/main (e8755651) 之上。

验证

自动化

  • cargo check -p bitfun-cli → 0 错误
  • npx tsc --noEmit → 0 错误
  • npx eslint src/flow_chat/components/ChatInput.tsx → 0 错误(含 react-hooks/exhaustive-deps
  • npx vitest run921/921 测试通过
  • node scripts/i18n-contract.test.mjs37/37 通过(i18n 治理契约,含 literal-fallback-baseline 检查)

手动(PR 合入后)

  1. 在 BitFun 打开聊天框
  2. 输入 /reload-skills + Enter
  3. 期望:右下角 toast Reloaded skills (N available),N 包含 workspace-level skills
  4. 输入 /reload-skills foo + Enter
  5. 期望:警告 toast Use /reload-skills without extra arguments.发送消息
  6. (可选)在文件系统里新建/修改一个 skill 文件(~/.bitfun/skills/<workspace>/.bitfun/skills/
  7. 再次输入 /reload-skills + Enter
  8. 期望:toast 数字增加,新 skill 在 picker 中可用

CLI 验证

cargo run -p bitfun-cli
> /reload-skills
[状态栏] Skills reloaded (N available)
[系统消息] Reloaded N skill(s) from disk.

Review 历程(4 轮迭代全部合并为这 1 commit)

轮次 触发 修复
1 独立 codex 静态审查 HIGH × 2(workspacePath、startsWith 警告)+ MEDIUM × 3(defaultValue 措辞、CLI 措辞、rt_handle 参数)
2 CI i18n 治理失败 去掉 5 处字符串字面量 defaultValue(i18n-literal-fallback-baseline 治理)
3 CI lint 失败 workspacePath 到 useCallback deps 数组(react-hooks/exhaustive-deps
4 rebase 到最新 main 应用本地 main 新加的 localSlashCommandsEnabled 守卫(/usage/init 等也用这个守卫)

注意

  • PR feat(web-ui): precise slash-command matcher #1023 (feat/precise-slash-command-matcher) 仍 OPEN 等待维护者 review,与本 PR 无关
  • 本 PR 不含 SkillRegistry 任何后端改动
  • 已知问题(pre-existing, 不在 scope):refresh_for_workspace(workspace_root)workspace_root 参数被忽略——已在 PR 描述中提及

jarvis24young added a commit to jarvis24young/BitFun that referenced this pull request Jun 3, 2026
The CI run for PR GCWing#1057 failed on the i18n audit subtest
'i18n audit can emit a machine-readable governance report':

  [i18n:audit] ERROR src/web-ui/src/flow_chat/components/ChatInput.tsx
    has 5 literal i18next defaultValue fallback(s) but is missing
    from scripts/i18n-literal-fallback-baseline.json.

BitFun's i18n governance treats literal defaultValue as a no-growth
guard (scripts/i18n-literal-fallback-baseline.json: "Add or repair
locale resources instead of raising this baseline"). A literal
defaultValue silently masks a missing translation — when the key is
absent, i18next returns the hardcoded English string from source
instead of failing the build. The fix is therefore never to use a
string literal as defaultValue when the key already exists in all
locales; the right pattern is plain `t('key')` (see siblings
`/usage`, `/init`, `/DeepReview` in the same array).

Strip the 5 defaultValue literals from the new /reload-skills calls.
The `count` interpolation in `reloadSkillsDone` is kept (it is a
real i18next interpolation, not a literal).

Verified:
- npx tsc --noEmit: 0 errors
- npx vitest run: 864/864 pass
- node scripts/i18n-contract.test.mjs: 37/37 pass (was 1/37 failing)
Mirrors Claude Code 2.1.152: a slash command that re-scans skill
directories from disk without requiring a session restart.

Both the CLI and the Web UI now expose the same command via a single
shared capability that was already in place end-to-end: the Tauri RPC
get_skill_configs(force_refresh: true) calls
SkillRegistry::global().refresh() and returns the new view, and
configAPI.getSkillConfigs({ forceRefresh: true }) wraps it on the
TS side. The only thing missing was a user-facing entry point on
both surfaces — this PR adds it.

Branch: feat/reload-skills-command, rebased on top of origin/main
(e875565). Single commit containing the full implementation.

---

CLI
- Register /reload-skills in COMMAND_SPECS.
- handle_command dispatches it to a new reload_skills_from_disk
  method that calls SkillRegistry::global().refresh() directly
  (no Tauri bridge needed in the CLI — it shares the same global
  registry as the desktop runtime) and shows a status line with
  the reloaded skill count. Not gated on is_processing: the cache
  swap is atomic and a held SkillInfo reference is not kept
  across the call.
- reload_skills_from_disk takes rt_handle as a parameter and uses
  it via rt_handle.block_on, matching the convention used by every
  other async CLI helper in this file.

Web UI
- New entry in getFilteredActions: id='reload-skills', command=
  '/reload-skills'. Picker-routed.
- selectSlashCommandAction sets the input to the bare command (no
  args); user presses Enter to dispatch.
- New submitReloadSkillsFromInput function modeled on
  submitUsageFromInput: validates the bare command, clears the
  input, calls configAPI.getSkillConfigs with both forceRefresh:
  true AND workspacePath so project-level skills (in
  .bitfun/skills/, .cursor/skills/, etc.) are included in the
  count, and surfaces success / failure via the existing
  notificationService toasts.
- New /reload-skills matcher in handleSendOrCancel wrapped in the
  localSlashCommandsEnabled guard (matching the existing /usage,
  /init, /DeepReview matcher pattern that landed on main while
  this branch was in review).
- New 'startsWith' warning for the '/reload-skills foo' case so
  the message does not fall through to the agent as a regular
  user message.
- i18n defaultValue fallbacks are kept as plain t('key') calls
  with no string-literal fallback — i18n audit governance
  (scripts/i18n-literal-fallback-baseline.json) treats literal
  defaultValue as anti-pattern because it silently masks
  missing translations.

i18n (4 keys × 3 locales = 12 insertions):
- chatInput.reloadSkillsAction  — picker label
- chatInput.reloadSkillsUsage   — arg-validation warning
- chatInput.reloadSkillsDone    — success toast (with {{count}})
- chatInput.reloadSkillsFailed  — failure toast title

---

Verification:
- cargo check -p bitfun-cli: 0 errors
- npx tsc --noEmit: 0 errors
- npx eslint src/flow_chat/components/ChatInput.tsx: 0 errors
  (incl. react-hooks/exhaustive-deps)
- npx vitest run: 921/921 pass
- node scripts/i18n-contract.test.mjs: 37/37 pass
  (incl. literal-fallback-baseline check)
@jarvis24young jarvis24young force-pushed the feat/reload-skills-command branch from 596c0de to fb7996c Compare June 4, 2026 01:32
@GCWing GCWing requested a review from wsp1911 June 4, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants