From 9e023b1af8cec41b4cf31fcc4e7f0a735ce7317b Mon Sep 17 00:00:00 2001 From: Cea <61349137+ceastld@users.noreply.github.com> Date: Wed, 23 Sep 2026 05:39:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(workbuddy):=20=E6=8E=A5=E5=85=A5=20WorkBud?= =?UTF-8?q?dy=20/=20CodeBuddy=20=E5=86=99=E5=8A=A8=E4=BD=9C=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - plugins/quicker-workbuddy:自包含插件,展开 CODEBUDDY_PLUGIN_ROOT,客户端身份为 workbuddy-quicker-plugin - shared 与各安装包:转接允许 workbuddy,并同步写动作连接说明 - 文档、发布清单与测试:登记市场入口、安装诊断和隔离启动 - 验证:python -m unittest discover -s tests -v,45 项通过 --- .codebuddy-plugin/marketplace.json | 17 ++ .github/workflows/test.yml | 6 + AGENTS.md | 2 +- README.md | 31 +- .../\345\205\274\345\256\271\346\200\247.md" | 13 +- "docs/\345\217\221\345\270\203.md" | 6 +- ...67\347\253\257\345\256\211\350\243\205.md" | 43 ++- ...45\345\205\245\347\272\246\345\256\232.md" | 2 +- ...60\345\242\236\345\271\263\345\217\260.md" | 2 +- .../quicker-claude/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- .../quicker-cursor/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- plugins/quicker-dsh/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- plugins/quicker-mcp/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- .../.codebuddy-plugin/plugin.json | 10 + plugins/quicker-workbuddy/.mcp.json | 18 ++ plugins/quicker-workbuddy/README.md | 47 +++ .../quicker-workbuddy/scripts/quicker-mcp.ps1 | 285 ++++++++++++++++++ .../skills/write-action/SKILL.md | 28 ++ .../write-action/references/connection.md | 18 ++ plugins/quicker/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- scripts/release-packages.json | 7 + shared/scripts/quicker-mcp.ps1 | 2 +- .../write-action/references/connection.md | 4 +- tests/test_install_clients.py | 8 +- 29 files changed, 548 insertions(+), 31 deletions(-) create mode 100644 .codebuddy-plugin/marketplace.json create mode 100644 plugins/quicker-workbuddy/.codebuddy-plugin/plugin.json create mode 100644 plugins/quicker-workbuddy/.mcp.json create mode 100644 plugins/quicker-workbuddy/README.md create mode 100644 plugins/quicker-workbuddy/scripts/quicker-mcp.ps1 create mode 100644 plugins/quicker-workbuddy/skills/write-action/SKILL.md create mode 100644 plugins/quicker-workbuddy/skills/write-action/references/connection.md diff --git a/.codebuddy-plugin/marketplace.json b/.codebuddy-plugin/marketplace.json new file mode 100644 index 0000000..aa124ad --- /dev/null +++ b/.codebuddy-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "quicker-agent-integrations", + "owner": { + "name": "QuickerOrg" + }, + "plugins": [ + { + "name": "quicker", + "source": "./plugins/quicker-workbuddy", + "version": "0.2.0", + "description": "通过本机 Quicker MCP 编写、保存和预览自动化动作。" + } + ], + "metadata": { + "description": "通过本机 Quicker 编写和预览自动化动作的插件。" + } +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6cca880..fff871b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,12 @@ jobs: if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } python -m json.tool plugins/quicker-dsh/package.json > $null if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + python -m json.tool .codebuddy-plugin/marketplace.json > $null + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + python -m json.tool plugins/quicker-workbuddy/.codebuddy-plugin/plugin.json > $null + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + python -m json.tool plugins/quicker-workbuddy/.mcp.json > $null + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - name: Test transport, installation and release packaging run: python -m unittest discover -s tests -v - name: Build and verify every release package diff --git a/AGENTS.md b/AGENTS.md index 7efd9b4..6c4914b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ This repository maintains integrations that let external agents use Quicker. Sta ## Boundaries -- Keep installable packages under plugins/ and make each directory self-contained. The Codex marketplace currently exposes plugins/quicker; DSH uses plugins/quicker-dsh as a cordis bundle. Declare each future platform's source path in its own catalog. +- Keep installable packages under plugins/ and make each directory self-contained. The Codex marketplace currently exposes plugins/quicker; WorkBuddy / CodeBuddy uses plugins/quicker-workbuddy via .codebuddy-plugin/marketplace.json; DSH uses plugins/quicker-dsh as a cordis bundle. Declare each future platform's source path in its own catalog. - Quicker owns action execution, step knowledge, permissions, approvals and Catalog state. Discover runtime knowledge instead of copying a static module catalog here. - Do not add Quicker product source, private repository dependencies, personal configuration, client grants, credentials or machine-specific paths. - Add shared source when a second real consumer needs it. Copy required runtime files into each distributable package; do not use symlinks or paths outside the installed package. diff --git a/README.md b/README.md index 8522cf8..d4720db 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 这个仓库集中维护各平台插件、安装与更新工具、MCP 接入约定、开发指南和契约测试。插件通过 Quicker 的公开接口工作,步骤知识由运行中的 Quicker 实时提供。 -提供 Codex、Cursor、Claude Code、DeepSeek Harness 插件及 VS Code / Gemini CLI 的 MCP 配置安装器,采用 [MIT 许可证](LICENSE)。 +提供 Codex、Cursor、Claude Code、WorkBuddy / CodeBuddy、DeepSeek Harness 插件及 VS Code / Gemini CLI 的 MCP 配置安装器,采用 [MIT 许可证](LICENSE)。 ## 支持情况 @@ -13,6 +13,7 @@ | Codex | 已实现,v0.2.0 | Windows;读取知识、编写/保存草稿、预览 | | Cursor | 本地插件;CLI 真实写动作通过 | Windows;技能、草稿创建/保存/预览 | | Claude Code | 原生插件,v0.2.1 | v0.2.0 公开市场安装和真实 MCP 连接通过;模型写动作待验收 | +| WorkBuddy / CodeBuddy | 原生插件,v0.2.0 | 本机 WorkBuddy 5.3.12 + CLI 2.115.0 安装并通过;模型改同一草稿已保存。桌面点选与公开 GitHub 市场未测 | | VS Code / Copilot、Gemini CLI | 配置安装器 | 默认 Windows 用户配置;尚未完成各客户端写动作验收 | | DeepSeek Harness | DSH bundle 插件,v0.2.4 | Windows;`write-action` 以技能目录卡片按需加载,不再在每次会话开头注入整份编写说明。真实 DSH 会话写动作待验收 | @@ -63,6 +64,31 @@ claude auth status Quicker 原生插件可与官方 [codex-plugin-cc](https://github.com/openai/codex-plugin-cc) 同时安装,前者直接提供 Quicker 工具,后者从 Claude Code 委托 Codex 审查或处理代码。两者不互为依赖,Codex 登录不能代替 Claude 登录。更新、连接超时处理及验收范围见[Claude Code 安装和诊断](docs/客户端安装.md#claude-code-安装和诊断)。 +## 安装 WorkBuddy / CodeBuddy 插件 + +WorkBuddy 桌面与 CodeBuddy CLI 共用同一插件引擎,安装命令是 `codebuddy`: + +```powershell +$env:CODEBUDDY_CONFIG_DIR = "$env:USERPROFILE\.workbuddy" +codebuddy plugin marketplace add QuickerOrg/quicker-agent-integrations +codebuddy plugin install quicker@quicker-agent-integrations --scope user +``` + +`marketplace add` 仓库本地路径会链到检出,不会进 `~\.workbuddy\plugins\cache\`。公开安装用 GitHub;本机未推送时用含 `.codebuddy-plugin/marketplace.json` 的 zip。 + +启用 Quicker 设置 → Agent 中的 MCP 与允许写入,执行 `/reload-plugins` 或新开会话,再用 `/mcp` 检查 Quicker。首次连接需要在 Quicker 中确认 `workbuddy-quicker-plugin` 客户端。不要在设置 → MCP 里填写 Quicker URL 或 token。 + +```powershell +codebuddy plugin list --json +codebuddy mcp list +``` + +可以这样开始: + +> 用 Quicker 写一个动作,显示“来自 WorkBuddy”,保存到暂存区并打开预览,不运行。 + +更新、卸载和诊断见[客户端安装](docs/客户端安装.md)。2026-09-16 已在本机 WorkBuddy 5.3.12 上完成安装、转接连接,以及模型改同一草稿并保存;桌面点选插件和公开 GitHub 市场安装尚未验收,范围见[兼容性说明](docs/兼容性.md)。 + ## 安装 DeepSeek Harness 插件 在 Windows PowerShell 中执行(需要 Git): @@ -164,6 +190,7 @@ codex plugin remove quicker@quicker-agent-integrations marketplace.json Codex Git 市场入口 plugins/ quicker/ Codex 完整安装单元 + quicker-workbuddy/ WorkBuddy / CodeBuddy 完整安装单元 quicker-dsh/ DeepSeek Harness bundle docs/ 接入约定.md 跨平台协议、权限、错误及动作编写约定 @@ -175,7 +202,7 @@ tests/ test_quicker_mcp.py 独立的传输契约测试 ``` -Cursor、Claude 和 Codex 分别由自己的 marketplace 清单声明包路径。DeepSeek Harness 使用 `plugins/quicker-dsh` 的 `dsh.bundle` 清单,不走那些市场。`shared/` 是传输与写动作技能的唯一源码,`python scripts/sync-packages.py` 同步到各自包含安装包,`--check` 在 CI 验证无漂移。 +Cursor、Claude、WorkBuddy / CodeBuddy 和 Codex 分别由自己的 marketplace 清单声明包路径。DeepSeek Harness 使用 `plugins/quicker-dsh` 的 `dsh.bundle` 清单,不走那些市场。`shared/` 是传输与写动作技能的唯一源码,`python scripts/sync-packages.py` 同步到各自包含安装包,`--check` 在 CI 验证无漂移。 ## 开发与验证 diff --git "a/docs/\345\205\274\345\256\271\346\200\247.md" "b/docs/\345\205\274\345\256\271\346\200\247.md" index 7f9429e..6d9c966 100644 --- "a/docs/\345\205\274\345\256\271\346\200\247.md" +++ "b/docs/\345\205\274\345\256\271\346\200\247.md" @@ -19,6 +19,7 @@ | 正式安装包端到端 | 尚未执行正式 MSI / 混淆 Release 的完整验收;不将内核测试或 Debug 草稿验收视为正式安装包已验证 | | Cursor CLI | 2026-09-07:2026.08.11-e8db854;v0.2.0 本地安装包技能加载、实时知识发现、4 步动作创建/保存/预览通过。IDE 3.7.12 的插件设置界面重载尚未单独操作验收 | | Claude Code | 2026-09-07:2.1.263;v0.2.0 插件与市场通过官方 validator,隔离安装及真实用户配置下的公开市场安装成功;识别 write-action 技能与 MCP,mcp list 连接真实 Quicker 成功。模型调用因未登录退出,未验证 Claude 模型写动作 | +| WorkBuddy / CodeBuddy | 2026-09-16:独立包 v0.2.0。本机 WorkBuddy 5.3.12(捆绑 CLI 2.115.0)从本地市场安装 `quicker@quicker-agent-integrations` 成功并启用。安装包转接连接真实 Quicker 2.2.13,19 个工具;创建/保存/预览草稿 `3Kyb`。CLI `--print` 发现 `mcp__quicker__*`;非交互默认拒绝 `DeferExecuteTool`,`bypassPermissions` 下模型读回并改同一草稿,`quicker_save` 返回 saved=true、editVersion=4。未运行动作。桌面会话点选插件未单独操作验收;`codebuddy mcp list` 不列出插件 MCP | | VS Code / Gemini CLI | v0.2.0 默认用户配置安装/更新/卸载和隔离传输通过;尚未完成实际客户端写动作验收 | | DeepSeek Harness | v0.2.4 将 `write-action` 注册为 DSH 技能目录卡片,完整说明按需加载,不再在 `agent/session-start` 注入整份正文;bundle 清单、安装器复制、`dsh` Client 转接与隔离传输通过。尚未完成真实 DSH 会话写动作验收 | @@ -26,7 +27,7 @@ 每个平台使用自己的插件 manifest 版本。发布记录应包含平台版本、Quicker 版本或构建、操作系统、插件版本与实测结果。尚未实测的最低版本写为未知,不猜测兼容范围。 -当前 Claude Code 安装包版本为 `0.2.1`,补齐安装、认证、诊断与共存指引,MCP 运行配置和共享转接与 `0.2.0` 相同。DeepSeek Harness 安装包为 `0.2.4`,写动作技能改为目录卡片按需加载。Codex / Cursor / 通用 MCP 仍为 `0.2.0`。各平台分发方式见[客户端安装](客户端安装.md)。旧个人市场原型使用的 `+codex.<时间戳>` 后缀只用于刷新开发缓存,不代表跨平台发布版本。 +当前 Claude Code 安装包版本为 `0.2.1`,补齐安装、认证、诊断与共存指引,MCP 运行配置和共享转接与 `0.2.0` 相同。WorkBuddy / CodeBuddy 安装包为 `0.2.0`。DeepSeek Harness 安装包为 `0.2.4`,写动作技能改为目录卡片按需加载。Codex / Cursor / 通用 MCP 仍为 `0.2.0`。各平台分发方式见[客户端安装](客户端安装.md)。旧个人市场原型使用的 `+codex.<时间戳>` 后缀只用于刷新开发缓存,不代表跨平台发布版本。 `0.1.1` 修复 `0.1.0` 安装成功但 MCP 无法启动的问题:当前 Codex legacy MCP 加载器不会展开参数中的 `${PLUGIN_ROOT}`,现改用 `cwd: "."` 与包内相对脚本路径。旧版用户按 README 的市场升级与重新安装步骤更新。隔离 HTTP fixture 用于传输回归,真实 Quicker 验收证据见下。 @@ -61,7 +62,7 @@ Quicker MCP 服务报告版本为 `2.3.0`,但本次使用包含默认技能包 Cursor CLI 从安装器生成的 `%USERPROFILE%/.cursor/plugins/local/quicker` 加载插件,读取 write-action skill 与服务端 action-source。生成“Cursor MCP 验收 · 文本摘要”,4 步完成参数文本修剪、字符数、非空行数和消息框摘要;校验保存到暂存区,quicker_preview 返回对应设计器。实际过程先出现 CLI print 模式自动拒绝;在专用测试目录授权需要的 Quicker 工具后成功,Quicker 权限和批准方式未修改。第一次源文本转义不当由 Cursor 读回发现并修正,保存结果 saved=true。动作未运行,因此这里不声称运行时统计已验收。 -Quicker 使用包含 MCP 与默认技能包发现修复的本地 Debug 构建,MCP 启用、允许写入、sandbox_confirm。新插件没有伪装已授权客户端;Client 参数分别发出 cursor-quicker-plugin / claude-quicker-plugin。所有原始日志只留本机,不提交个人配置或 token。 +Quicker 使用包含 MCP 与默认技能包发现修复的本地 Debug 构建,MCP 启用、允许写入、sandbox_confirm。新插件没有伪装已授权客户端;Client 参数分别发出 cursor-quicker-plugin / claude-quicker-plugin / workbuddy-quicker-plugin。所有原始日志只留本机,不提交个人配置或 token。 Claude Code 初次 npm 包缺少可选原生二进制;安装对应 Windows x64 2.1.263 包后官方校验、安装和 MCP 健康检查成功。首次默认 30 秒连接超时,使用该客户端 MCP_TIMEOUT=180000 复验 Connected;该变量只用于验收进程,没有修改全局权限或客户端配置。首次连接应留意 Quicker 的同意窗口。 @@ -81,4 +82,12 @@ Claude Code 初次 npm 包缺少可选原生二进制;安装对应 Windows x64 0.2.1 在 Windows 上的 23 项测试通过,新增启动回归将 Cursor / Claude 的完整安装包复制到含中文和空格的缓存目录,再从无关工作目录按实际 manifest 参数启动。Claude Code 2.1.263 对根市场和 Claude 插件的严格清单校验通过。这些结果不替代 Claude 的真实模型验收。 +## WorkBuddy 本机验收 + +2026-09-16,Windows。WorkBuddy 桌面 5.3.12(`a981f41f`),捆绑 `@genie/agent-cli` 报版本 2.115.0。`CODEBUDDY_CONFIG_DIR` 指向 `%USERPROFILE%\.workbuddy`。先从本地目录市场安装时,`installPath` 指向开发检出的 `plugins/quicker-workbuddy`(directory 市场不复制到 cache)。随后卸掉该市场,改用 zip 市场重装同一插件 0.2.0,`installPath` 为 `%USERPROFILE%\.workbuddy\plugins\cache\quicker-agent-integrations\quicker\0.2.0`,与官方插件同层。`enabledPlugins` 已打开。 + +`codebuddy plugin validate` 通过;市场清单缺 `plugins[0].version` 仅警告。Quicker Debug,MCP 启用、允许写入、`sandbox_confirm`,服务版本 `2.2.13`。转接 `-Client workbuddy` 初始化 19 个工具并 `skill_load(action-source)`。创建「WorkBuddy 真机验收 · 提示」,slot `3Kyb`,actionId `1d5ad76f-a95c-4a60-9b72-f1761a6ab05c`。按运行时糖写入 `notify:` 后 `quicker_save` 成功;`quicker_preview` 返回 `http://127.0.0.1:5174/designer/`。浏览器打开该 URL 时落到 Headless 对话页,未当作设计器画布验收。 + +同一环境 `codebuddy -p` 已登录。工具名为 `mcp__quicker__*`。默认 `--permission-mode auto` 因 `DeferExecuteTool` 无弹窗失败;`--permission-mode bypassPermissions` 下模型读回步骤原文,并改 `info.yaml` 说明后保存,`saved=true`、`editVersion=4`、仍是同一 actionId/slot。未 promote、未 overwrite、未运行。公开 GitHub `marketplace add owner/repo` 与桌面 UI 点选插件未测。 + 本次变更使用官方 `codex-plugin-cc` 1.0.6 调用 Codex 完成只读审查,未发现本次改动引入的明确缺陷;审查同时确认清单、共享副本一致性与 Python 语法检查通过。审查环境未重跑完整测试,23 项测试结果来自本仓库的独立 Windows 验证。 diff --git "a/docs/\345\217\221\345\270\203.md" "b/docs/\345\217\221\345\270\203.md" index 2f7c32c..f20e143 100644 --- "a/docs/\345\217\221\345\270\203.md" +++ "b/docs/\345\217\221\345\270\203.md" @@ -1,6 +1,6 @@ # 发布完整插件集合 -每次 GitHub Release 都必须提供 **Codex、Cursor、Claude Code、通用 MCP、DeepSeek Harness 的全部独立 ZIP**,即使本次只修改其中一个插件。最新 Release 应能直接找到所有平台的安装包,不能要求用户到旧版本寻找其他插件。 +每次 GitHub Release 都必须提供 **Codex、Cursor、Claude Code、WorkBuddy / CodeBuddy、通用 MCP、DeepSeek Harness 的全部独立 ZIP**,即使本次只修改其中一个插件。最新 Release 应能直接找到所有平台的安装包,不能要求用户到旧版本寻找其他插件。 ## 单一清单与版本 @@ -8,10 +8,10 @@ 文件名统一使用发布批次版本。**本次有改动的插件,manifest 版本必须与 tag 去掉 `v` 后的批次相同**(`v0.2.3` 改 DSH → 包内也是 `0.2.3`,对应 `quicker-dsh-0.2.3.zip`)。未改动的插件不要为凑齐附件而升版本;它们的 ZIP 文件名仍用批次号,包内保持原版本。`release-manifest.json` 分别记录 `releaseVersion`、各包 `packageVersion`、源 tag / commit、附件名、大小和 SHA-256。 -当前每批必须有 8 个附件: +当前每批必须有 9 个附件: - `quicker-agent-integrations-<发布版本>.zip`:完整源码安装包,含各平台包、安装器、市场入口、文档与许可证。 -- `quicker-codex-<发布版本>.zip`、`quicker-cursor-<发布版本>.zip`、`quicker-claude-<发布版本>.zip`、`quicker-mcp-<发布版本>.zip`、`quicker-dsh-<发布版本>.zip`:所有独立包。 +- `quicker-codex-<发布版本>.zip`、`quicker-cursor-<发布版本>.zip`、`quicker-claude-<发布版本>.zip`、`quicker-workbuddy-<发布版本>.zip`、`quicker-mcp-<发布版本>.zip`、`quicker-dsh-<发布版本>.zip`:所有独立包。 - `release-manifest.json`:可审查的批次与包版本记录。 - `SHA256SUMS.txt`:覆盖全部 ZIP 及发布清单。 diff --git "a/docs/\345\256\242\346\210\267\347\253\257\345\256\211\350\243\205.md" "b/docs/\345\256\242\346\210\267\347\253\257\345\256\211\350\243\205.md" index 4561aea..48eb191 100644 --- "a/docs/\345\256\242\346\210\267\347\253\257\345\256\211\350\243\205.md" +++ "b/docs/\345\256\242\346\210\267\347\253\257\345\256\211\350\243\205.md" @@ -8,11 +8,12 @@ | --- | --- | --- | | Cursor | plugins/quicker-cursor | `.cursor-plugin/plugin.json` + `mcp.json` + skills;本地目录或显式 `--plugin-dir` | | Claude Code | plugins/quicker-claude | `.claude-plugin/plugin.json` + `.mcp.json` + skills;原生市场 | +| WorkBuddy / CodeBuddy | plugins/quicker-workbuddy | `.codebuddy-plugin/plugin.json` + `.mcp.json` + skills;原生市场 | | Codex | plugins/quicker | `.codex-plugin/plugin.json` + `.mcp.json` + skills;原生市场 | | VS Code / Gemini CLI | plugins/quicker-mcp | 安装本地 stdio 转接并合并客户端 MCP JSON;编写规则来自 MCP initialize 与 skill_load | | DeepSeek Harness | plugins/quicker-dsh | `package.json` 的 `dsh.bundle` + `cordis.patch.yml` + `index.js`;安装器复制到本机目录,再 `dsh plugin --profile web add link:…` | -Cursor 和 Claude 分别展开 `${CURSOR_PLUGIN_ROOT}`、`${CLAUDE_PLUGIN_ROOT}`,Codex 使用包内相对 cwd。安装后各包独立运行,不访问 shared/ 或开发检出。 +Cursor、Claude 和 WorkBuddy 分别展开 `${CURSOR_PLUGIN_ROOT}`、`${CLAUDE_PLUGIN_ROOT}`、`${CODEBUDDY_PLUGIN_ROOT}`,Codex 使用包内相对 cwd。安装后各包独立运行,不访问 shared/ 或开发检出。 ## 安装器的范围 @@ -45,7 +46,7 @@ VS Code 的服务项还需 `"type": "stdio"`。不填 URL、Authorization 或 to powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/install-client.ps1 -Client cursor -Uninstall ``` -VS Code / Gemini / DSH 同样替换 Client。卸载只删除归属匹配且未编辑的当前包与对应 MCP 项,保留其他配置与旧备份。DSH 还会尝试 `dsh plugin --profile web remove dsh-plugin-quicker`。Codex 和 Claude Code 使用各自原生插件卸载命令。 +VS Code / Gemini / DSH 同样替换 Client。卸载只删除归属匹配且未编辑的当前包与对应 MCP 项,保留其他配置与旧备份。DSH 还会尝试 `dsh plugin --profile web remove dsh-plugin-quicker`。Codex、Claude Code 和 WorkBuddy / CodeBuddy 使用各自原生插件卸载命令。 ## DeepSeek Harness 安装和诊断 @@ -115,10 +116,48 @@ claude plugin uninstall quicker@quicker-agent-integrations --scope user 真实验收请按[兼容性记录](兼容性.md)区分插件安装、MCP 健康和模型写动作。不要将 `Not logged in`、Claude 工具自动拒绝与 Quicker HTTP 403 混为一类错误。 +## WorkBuddy / CodeBuddy 安装和诊断 + +原生市场和插件安装命令。WorkBuddy 桌面把配置写在 `%USERPROFILE%\.workbuddy`,CLI 需先设 `CODEBUDDY_CONFIG_DIR`,否则会装到另一套目录: + +```powershell +$env:CODEBUDDY_CONFIG_DIR = "$env:USERPROFILE\.workbuddy" +codebuddy plugin marketplace add QuickerOrg/quicker-agent-integrations +codebuddy plugin install quicker@quicker-agent-integrations --scope user +``` + +`marketplace add` 给仓库根路径时是 **directory** 市场:插件 `installPath` 直接指向检出,不会进 `~\.workbuddy\plugins\cache\`,桌面里看起来像“在本地仓库找插件”。正式安装用 GitHub `owner/repo`,或把含 `.codebuddy-plugin/marketplace.json` 与 `plugins/quicker-workbuddy` 的 zip 交给 `marketplace add`;装完后 `installPath` 应类似 `~\.workbuddy\plugins\cache\quicker-agent-integrations\quicker\0.2.0`。 + +仓库必须包含 `.codebuddy-plugin/marketplace.json`。开发校验用 `codebuddy plugin validate <仓库>/plugins/quicker-workbuddy`,不要用 `--plugin-dir` 当桌面安装。 + +在 Quicker 设置 → Agent 启用 MCP 与允许写入,首次连接确认 `workbuddy-quicker-plugin`。执行 `/reload-plugins` 或新开会话,用 `/mcp` 查看工具: + +| 检查 | 命令 | 判断方式 | +| --- | --- | --- | +| 插件加载 | `codebuddy plugin list --json` | `quicker@quicker-agent-integrations` 已安装、已启用 | +| MCP 连接 | 会话中的 `/mcp` | 出现 `mcp__quicker__*`。`codebuddy mcp list` 只列用户级 MCP,不列插件 MCP | +| 动作编写 | 在会话请求写测试草稿,或 `/quicker:write-action` 加需求 | 加载实时知识,创建、保存、读回并打开预览;默认不运行 | + +不要在 WorkBuddy 设置 → MCP 中填写 Quicker 的 HTTP URL 或 Bearer token。token 由包内转接读取。桌面端若只提供 URL 添加框、无法加载 CodeBuddy 插件,记为未覆盖路径,不要改 Quicker 授权文件绕过。 + +更新和卸载: + +```powershell +codebuddy plugin marketplace update quicker-agent-integrations +codebuddy plugin update quicker@quicker-agent-integrations --scope user +# 需要卸载时: +codebuddy plugin uninstall quicker@quicker-agent-integrations --scope user +``` + +`codebuddy mcp list` 只显示用户级 `.mcp.json`,不列出插件 MCP。插件工具在会话里以 `mcp__quicker__<名>` 出现,且可能延迟加载。`--print` 非交互默认无法批准 `DeferExecuteTool`;验收可用 `--permission-mode bypassPermissions`,不要改 Quicker 的 `server.json` / `clients.json`。 + +真实验收见[兼容性记录](兼容性.md)。 + ## 官方依据 - [Cursor 插件清单、MCP 和本地安装](https://cursor.com/docs/reference/plugins),[本地插件目录](https://cursor.com/docs/plugins#test-plugins-locally),[CLI MCP 权限](https://cursor.com/docs/cli/reference/permissions)。 - [Claude Code 插件与 MCP](https://code.claude.com/docs/en/plugins-reference)、[市场 CLI](https://code.claude.com/docs/en/plugin-marketplaces#manage-marketplaces-from-the-cli)、[认证](https://code.claude.com/docs/en/authentication)。 +- [WorkBuddy / CodeBuddy 插件](https://www.workbuddy.ai/docs/cli/plugins-reference)、[市场](https://www.workbuddy.ai/docs/cli/plugin-marketplaces)、[MCP](https://www.workbuddy.ai/docs/cli/mcp)。 - [VS Code MCP 配置](https://code.visualstudio.com/docs/agent-customization/mcp-servers)。 - [Gemini CLI MCP 配置](https://geminicli.com/docs/tools/mcp-server/)。 - [DeepSeek Harness 插件打包](https://deepseek-harness.github.io/deepseek-harness/en/develop/basic/publish)、[MCP client](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/mcp-client/README.md)。 diff --git "a/docs/\346\216\245\345\205\245\347\272\246\345\256\232.md" "b/docs/\346\216\245\345\205\245\347\272\246\345\256\232.md" index c22ccc8..6ed0790 100644 --- "a/docs/\346\216\245\345\205\245\347\272\246\345\256\232.md" +++ "b/docs/\346\216\245\345\205\245\347\272\246\345\256\232.md" @@ -2,7 +2,7 @@ 本仓库维护外部 Agent 的连接、安装与使用引导。Quicker 提供动作工具、实时知识、草稿存储和审批。各平台适配遵循本文,平台交付要求见[新增平台](新增平台.md)。 -Codex 插件 0.1.1 已通过原生安装及真实 Quicker Debug 草稿编写、保存和预览验收,Cursor、Claude Code、DeepSeek Harness 与通用 MCP 安装器现由同一共享源码生成。使用前确认 Quicker 的设置 → Agent 中有「启用 MCP」入口,并使用包含默认技能包发现修复的新构建;不能仅凭 `2.3.0` 版本号判断兼容。 +Codex 插件 0.1.1 已通过原生安装及真实 Quicker Debug 草稿编写、保存和预览验收,Cursor、Claude Code、WorkBuddy / CodeBuddy、DeepSeek Harness 与通用 MCP 安装器现由同一共享源码生成。使用前确认 Quicker 的设置 → Agent 中有「启用 MCP」入口,并使用包含默认技能包发现修复的新构建;不能仅凭 `2.3.0` 版本号判断兼容。 Release 支持已实现,待包含这些变更的正式版发布;已发布旧版没有 MCP 入口时仍不可用。新构建的 Debug / Release 均默认关闭 MCP,由用户在设置中启用;安装插件不会开启服务或写入权限。具体构建、测试与正式发布情况见[兼容性说明](兼容性.md)。 diff --git "a/docs/\346\226\260\345\242\236\345\271\263\345\217\260.md" "b/docs/\346\226\260\345\242\236\345\271\263\345\217\260.md" index ad58b35..9473cc9 100644 --- "a/docs/\346\226\260\345\242\236\345\271\263\345\217\260.md" +++ "b/docs/\346\226\260\345\242\236\345\271\263\345\217\260.md" @@ -28,7 +28,7 @@ ## 共享的时机 -当前 shared/ 保存转接与技能唯一源码,sync-packages.py 复制到 Codex / Cursor / Claude / 通用 MCP / DeepSeek Harness 安装单元。平台身份由受限 Client 参数指定;清单与重载方式各自维护。 +当前 shared/ 保存转接与技能唯一源码,sync-packages.py 复制到 Codex / Cursor / Claude / WorkBuddy / 通用 MCP / DeepSeek Harness 安装单元。平台身份由受限 Client 参数指定;清单与重载方式各自维护。 若提取到 `shared/`,指定唯一源码,通过一个确定的打包步骤复制到各安装单元;验证复制结果与源码一致,并测试最终包。不要手工维护多份转接实现,也不要为尚未开发的平台预建抽象框架。 diff --git a/plugins/quicker-claude/scripts/quicker-mcp.ps1 b/plugins/quicker-claude/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/plugins/quicker-claude/scripts/quicker-mcp.ps1 +++ b/plugins/quicker-claude/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/plugins/quicker-claude/skills/write-action/references/connection.md b/plugins/quicker-claude/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/plugins/quicker-claude/skills/write-action/references/connection.md +++ b/plugins/quicker-claude/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/plugins/quicker-cursor/scripts/quicker-mcp.ps1 b/plugins/quicker-cursor/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/plugins/quicker-cursor/scripts/quicker-mcp.ps1 +++ b/plugins/quicker-cursor/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/plugins/quicker-cursor/skills/write-action/references/connection.md b/plugins/quicker-cursor/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/plugins/quicker-cursor/skills/write-action/references/connection.md +++ b/plugins/quicker-cursor/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/plugins/quicker-dsh/scripts/quicker-mcp.ps1 b/plugins/quicker-dsh/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/plugins/quicker-dsh/scripts/quicker-mcp.ps1 +++ b/plugins/quicker-dsh/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/plugins/quicker-dsh/skills/write-action/references/connection.md b/plugins/quicker-dsh/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/plugins/quicker-dsh/skills/write-action/references/connection.md +++ b/plugins/quicker-dsh/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/plugins/quicker-mcp/scripts/quicker-mcp.ps1 b/plugins/quicker-mcp/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/plugins/quicker-mcp/scripts/quicker-mcp.ps1 +++ b/plugins/quicker-mcp/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/plugins/quicker-mcp/skills/write-action/references/connection.md b/plugins/quicker-mcp/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/plugins/quicker-mcp/skills/write-action/references/connection.md +++ b/plugins/quicker-mcp/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/plugins/quicker-workbuddy/.codebuddy-plugin/plugin.json b/plugins/quicker-workbuddy/.codebuddy-plugin/plugin.json new file mode 100644 index 0000000..88f1309 --- /dev/null +++ b/plugins/quicker-workbuddy/.codebuddy-plugin/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "quicker", + "version": "0.2.0", + "description": "通过本机 Quicker MCP 编写、保存和预览自动化动作。", + "author": { + "name": "QuickerOrg" + }, + "license": "MIT", + "repository": "https://github.com/QuickerOrg/quicker-agent-integrations" +} diff --git a/plugins/quicker-workbuddy/.mcp.json b/plugins/quicker-workbuddy/.mcp.json new file mode 100644 index 0000000..a16a299 --- /dev/null +++ b/plugins/quicker-workbuddy/.mcp.json @@ -0,0 +1,18 @@ +{ + "mcpServers": { + "quicker": { + "command": "powershell.exe", + "args": [ + "-NoLogo", + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", + "Bypass", + "-File", + "${CODEBUDDY_PLUGIN_ROOT}/scripts/quicker-mcp.ps1", + "-Client", + "workbuddy" + ] + } + } +} diff --git a/plugins/quicker-workbuddy/README.md b/plugins/quicker-workbuddy/README.md new file mode 100644 index 0000000..aa97547 --- /dev/null +++ b/plugins/quicker-workbuddy/README.md @@ -0,0 +1,47 @@ +# Quicker WorkBuddy / CodeBuddy 插件 + +版本:0.2.0。需要 Windows PowerShell 5.1、WorkBuddy 或 CodeBuddy CLI,以及设置 → Agent 中带「启用 MCP」入口的本机 Quicker。此目录包含完整转接与技能,运行时不依赖开发检出、Git、Python 或 Node。 + +WorkBuddy 桌面与 CodeBuddy CLI 共用同一套插件引擎。安装命令是 `codebuddy`。 + +## 安装和开始编写 + +桌面端先设 `CODEBUDDY_CONFIG_DIR` 为 `%USERPROFILE%\.workbuddy`。用 GitHub `owner/repo` 或含市场清单的 zip 添加市场,不要 `marketplace add` 仓库根路径(那会链到检出,不会进 cache): + +```powershell +$env:CODEBUDDY_CONFIG_DIR = "$env:USERPROFILE\.workbuddy" +codebuddy plugin marketplace add QuickerOrg/quicker-agent-integrations +codebuddy plugin install quicker@quicker-agent-integrations --scope user +``` + +启用 Quicker 设置 → Agent 中的 MCP 与允许写入,然后执行 `/reload-plugins` 或新开会话。首次连接时,在 Quicker 中确认 `workbuddy-quicker-plugin` 客户端;安装本身不授予执行或覆盖权限。 + +分别检查安装和连接: + +```powershell +codebuddy plugin list --json +codebuddy mcp list +``` + +插件应为 `quicker@quicker-agent-integrations` 且已启用。在 `/mcp` 或 `/plugin` 中确认 quicker 后,可直接请求: + +> 用 Quicker 写一个动作,显示“来自 WorkBuddy”,保存到暂存区并打开预览,不运行。 + +也可以执行 `/quicker:write-action` 加上需求。结果默认保存为草稿;正式保留、覆盖原动作或运行由用户要求及 Quicker 审批决定。 + +不要在 WorkBuddy 设置 → MCP 里填写 Quicker 的 URL 和 token。token 由包内转接每次从本机读取。 + +## 更新、卸载和诊断 + +```powershell +codebuddy plugin marketplace update quicker-agent-integrations +codebuddy plugin update quicker@quicker-agent-integrations --scope user +``` + +更新后执行 `/reload-plugins` 或新开会话。卸载使用 `codebuddy plugin uninstall quicker@quicker-agent-integrations --scope user`。 + +首次连接超时时,先查看 Quicker 的客户端同意窗口。HTTP 403 表示 Quicker 端同意未完成。不要修改 Quicker 配置文件来授予权限。 + +各版本真实验收范围见[兼容性说明](https://github.com/QuickerOrg/quicker-agent-integrations/blob/main/docs/兼容性.md)。 + +传输脚本与技能由 shared/ 生成;维护时运行 scripts/sync-packages.py,不手工修改副本。 diff --git a/plugins/quicker-workbuddy/scripts/quicker-mcp.ps1 b/plugins/quicker-workbuddy/scripts/quicker-mcp.ps1 new file mode 100644 index 0000000..f6a4e61 --- /dev/null +++ b/plugins/quicker-workbuddy/scripts/quicker-mcp.ps1 @@ -0,0 +1,285 @@ +[CmdletBinding()] +param( + [string]$SettingsPath = '', + [ValidateRange(1, 600)] + [int]$RequestTimeoutSeconds = 180, + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] + [string]$Client = 'codex', + [switch]$Check +) + +# A transport adapter only: Quicker owns tools, authoring state and approval policy. +# Keep JSON payloads as text so Windows PowerShell never rewrites schemas or numbers. +$ErrorActionPreference = 'Stop' +$ProgressPreference = 'SilentlyContinue' +$utf8 = New-Object System.Text.UTF8Encoding($false) +[Console]::InputEncoding = $utf8 +[Console]::OutputEncoding = $utf8 +$OutputEncoding = $utf8 +Add-Type -AssemblyName System.Web.Extensions +$jsonReader = New-Object System.Web.Script.Serialization.JavaScriptSerializer +$jsonReader.MaxJsonLength = [int]::MaxValue +$jsonReader.RecursionLimit = 256 +if ([string]::IsNullOrWhiteSpace($SettingsPath)) { + $SettingsPath = Join-Path ([Environment]::GetFolderPath('UserProfile')) '.quicker\mcp\server.json' +} + +function Write-ProtocolLine([string]$Text) { + [Console]::Out.WriteLine($Text) + [Console]::Out.Flush() +} + +function Compress-JsonText([string]$Text) { + $builder = New-Object System.Text.StringBuilder + $inString = $false + $escaped = $false + foreach ($character in $Text.ToCharArray()) { + if ($inString) { + [void]$builder.Append($character) + if ($escaped) { $escaped = $false } + elseif ($character -eq '\') { $escaped = $true } + elseif ($character -eq '"') { $inString = $false } + } + elseif ($character -eq '"') { + $inString = $true + [void]$builder.Append($character) + } + elseif (-not [char]::IsWhiteSpace($character)) { [void]$builder.Append($character) } + } + return $builder.ToString() +} + +function Get-RpcIdText([string]$Text) { + # Read only the top-level id token, preserving a numeric id's exact spelling. + $depth = 0 + for ($index = 0; $index -lt $Text.Length; $index++) { + $character = $Text[$index] + if ($character -eq '{' -or $character -eq '[') { $depth++; continue } + if ($character -eq '}' -or $character -eq ']') { $depth--; continue } + if ($character -ne '"') { continue } + $start = $index + $index++ + for (; $index -lt $Text.Length; $index++) { + if ($Text[$index] -eq '\') { $index++; continue } + if ($Text[$index] -eq '"') { break } + } + if ($depth -ne 1) { continue } + $after = $index + 1 + while ($after -lt $Text.Length -and [char]::IsWhiteSpace($Text[$after])) { $after++ } + if ($after -ge $Text.Length -or $Text[$after] -ne ':') { continue } + $keyToken = $Text.Substring($start, $index - $start + 1) + $key = $jsonReader.DeserializeObject('{"key":' + $keyToken + '}') + if ($key.key -cne 'id') { continue } + $valueStart = $after + 1 + while ($valueStart -lt $Text.Length -and [char]::IsWhiteSpace($Text[$valueStart])) { $valueStart++ } + $valueEnd = $valueStart + if ($Text[$valueStart] -eq '"') { + $valueEnd++ + for (; $valueEnd -lt $Text.Length; $valueEnd++) { + if ($Text[$valueEnd] -eq '\') { $valueEnd++; continue } + if ($Text[$valueEnd] -eq '"') { $valueEnd++; break } + } + } + else { + while ($valueEnd -lt $Text.Length -and $Text[$valueEnd] -ne ',' -and $Text[$valueEnd] -ne '}') { $valueEnd++ } + } + return $Text.Substring($valueStart, $valueEnd - $valueStart).Trim() + } + return $null +} + +function Write-RpcFailure { + param([string]$IdText, [int]$Code, [string]$FailureCode, [string]$Message, + [bool]$StateUnknown = $false, [int]$HttpStatus = 0) + if ([string]::IsNullOrEmpty($IdText)) { + # Notifications must not receive JSON-RPC replies. Diagnostics never contain input data. + [Console]::Error.WriteLine('Quicker MCP: ' + $FailureCode + '. ' + $Message) + return + } + $data = [ordered]@{ code = $FailureCode; stateUnknown = $StateUnknown } + if ($HttpStatus -ne 0) { $data.httpStatus = $HttpStatus } + $errorBody = [ordered]@{ code = $Code; message = $Message; data = $data } | ConvertTo-Json -Depth 8 -Compress + Write-ProtocolLine ('{"jsonrpc":"2.0","id":' + $IdText + ',"error":' + $errorBody + '}') +} + +function Read-McpSettings { + if (-not [System.IO.File]::Exists($SettingsPath)) { + return @{ Code = 'settings_missing'; Message = 'Enable MCP Server in a Debug build of Quicker first.' } + } + try { + $settings = $jsonReader.DeserializeObject([System.IO.File]::ReadAllText($SettingsPath, $utf8)) + if ($null -eq $settings -or $settings -is [array]) { throw 'invalid' } + $port = 0 + if (-not [int]::TryParse([string]$settings.Port, [ref]$port) -or $port -lt 1024 -or $port -gt 65535) { + throw 'invalid' + } + $tokenPresent = $settings.Token -is [string] -and -not [string]::IsNullOrWhiteSpace($settings.Token) + if ($tokenPresent -and $settings.Token -match '\s') { throw 'invalid' } + $enabled = $settings.Enabled -is [bool] -and $settings.Enabled + $allowWrites = $settings.AllowWrites -is [bool] -and $settings.AllowWrites + return @{ Enabled = $enabled; AllowWrites = $allowWrites; Port = $port; + TokenPresent = $tokenPresent; Token = $settings.Token } + } + catch { + return @{ Code = 'settings_invalid'; Message = 'Quicker MCP settings could not be read. Check them in Quicker.' } + } +} + +if ($Check) { + $settings = Read-McpSettings + if ($settings.Code) { + Write-ProtocolLine (([ordered]@{ ok = $false; code = $settings.Code; message = $settings.Message }) | ConvertTo-Json -Compress) + exit 1 + } + $reachable = $false + $tcpClient = New-Object System.Net.Sockets.TcpClient + try { + $pending = $tcpClient.BeginConnect('127.0.0.1', $settings.Port, $null, $null) + if ($pending.AsyncWaitHandle.WaitOne(2000)) { + $tcpClient.EndConnect($pending) + $reachable = $tcpClient.Connected + } + $pending.AsyncWaitHandle.Close() + } + catch { $reachable = $false } + finally { $tcpClient.Close() } + $ready = $settings.Enabled -and $settings.TokenPresent -and $reachable + Write-ProtocolLine (([ordered]@{ ok = [bool]$ready; enabled = [bool]$settings.Enabled; + allowWrites = [bool]$settings.AllowWrites; port = $settings.Port; + tokenPresent = [bool]$settings.TokenPresent; portReachable = $reachable }) | ConvertTo-Json -Compress) + if ($ready) { exit 0 } + exit 1 +} + +$protocolVersion = $null +while ($null -ne ($line = [Console]::In.ReadLine())) { + if ([string]::IsNullOrWhiteSpace($line)) { continue } + $idText = $null + try { + $rpc = $jsonReader.DeserializeObject($line) + $idText = Get-RpcIdText $line + if ($null -eq $rpc -or $rpc -is [array] -or $rpc.jsonrpc -cne '2.0' -or + $rpc.method -isnot [string] -or [string]::IsNullOrWhiteSpace($rpc.method)) { + throw 'invalid request' + } + if ($null -ne $rpc.id -and ($rpc.id -is [bool] -or ($rpc.id -isnot [string] -and $rpc.id -isnot [ValueType]))) { throw 'invalid id' } + } + catch { + Write-RpcFailure -IdText 'null' -Code -32600 -FailureCode 'invalid_request' -Message 'Expected one JSON-RPC 2.0 request or notification per line.' + continue + } + + $settings = Read-McpSettings + if ($settings.Code) { + Write-RpcFailure -IdText $idText -Code -32001 -FailureCode $settings.Code -Message $settings.Message + continue + } + if (-not $settings.Enabled) { + Write-RpcFailure -IdText $idText -Code -32001 -FailureCode 'server_disabled' -Message 'Enable MCP Server in Quicker settings.' + continue + } + if (-not $settings.TokenPresent) { + Write-RpcFailure -IdText $idText -Code -32001 -FailureCode 'token_missing' -Message 'Quicker MCP has no token. Check MCP Server settings in Quicker.' + continue + } + + $request = $null + $response = $null + $mayHaveSent = $false + $forwardedResponse = $false + try { + # Only the persisted port is configurable. Never send the token to another host, + # an HTTP proxy, or a redirect target. + $request = [System.Net.HttpWebRequest]::Create('http://127.0.0.1:' + $settings.Port + '/mcp') + $request.Method = 'POST' + $request.Proxy = $null + $request.AllowAutoRedirect = $false + # Avoid automatic replay when a reused keep-alive socket is closed by the server. + $request.KeepAlive = $false + $request.Timeout = $RequestTimeoutSeconds * 1000 + $request.ReadWriteTimeout = $RequestTimeoutSeconds * 1000 + $request.ContentType = 'application/json; charset=utf-8' + $request.Accept = 'application/json, text/event-stream' + $request.Headers['Authorization'] = 'Bearer ' + $settings.Token + $request.Headers['Mcp-Client-Info'] = ($Client + '-quicker-plugin') + if ($protocolVersion) { $request.Headers['MCP-Protocol-Version'] = $protocolVersion } + $request.ServicePoint.Expect100Continue = $false + $bytes = $utf8.GetBytes($line) + $request.ContentLength = $bytes.Length + $mayHaveSent = $true + $stream = $request.GetRequestStream() + try { $stream.Write($bytes, 0, $bytes.Length) } + finally { $stream.Dispose() } + try { $response = $request.GetResponse() } + catch [System.Net.WebException] { + if ($null -eq $_.Exception.Response) { throw } + $response = $_.Exception.Response + } + $status = [int]$response.StatusCode + if ($status -lt 200 -or $status -ge 300) { + $failureCode = 'http_error' + $message = 'Quicker MCP rejected the HTTP request. Check Quicker before retrying.' + $stateUnknown = $status -ge 500 + if ($status -eq 401) { $failureCode = 'unauthorized'; $message = 'Quicker rejected the MCP token. Check MCP settings in Quicker.' } + elseif ($status -eq 403) { $failureCode = 'client_not_approved'; $message = 'Approve the connecting MCP client in Quicker, then reconnect.' } + elseif ($status -ge 300 -and $status -lt 400) { $failureCode = 'redirect_refused'; $message = 'Quicker MCP returned a redirect. Redirects are refused; check the local endpoint.' } + Write-RpcFailure -IdText $idText -Code -32003 -FailureCode $failureCode -Message $message -StateUnknown $stateUnknown -HttpStatus $status + continue + } + if ($status -eq 202) { + if ($idText) { throw 'missing response' } + continue + } + $reader = New-Object System.IO.StreamReader($response.GetResponseStream(), $utf8) + try { $body = $reader.ReadToEnd() } + finally { $reader.Dispose() } + if ([string]::IsNullOrWhiteSpace($body)) { + if ($idText) { throw 'missing response' } + continue + } + $payloads = New-Object 'System.Collections.Generic.List[string]' + if ($response.ContentType -match '^text/event-stream(?:;|$)') { + $eventData = New-Object 'System.Collections.Generic.List[string]' + foreach ($eventLine in ($body -split '\r\n|\n|\r')) { + if ($eventLine.Length -eq 0) { + if ($eventData.Count -gt 0) { $payloads.Add(($eventData -join "`n")); $eventData.Clear() } + } + elseif ($eventLine.StartsWith('data:')) { + $value = $eventLine.Substring(5) + if ($value.StartsWith(' ')) { $value = $value.Substring(1) } + $eventData.Add($value) + } + } + if ($eventData.Count -gt 0) { $payloads.Add(($eventData -join "`n")) } + } + elseif ($response.ContentType -match '^application/json(?:;|$)') { $payloads.Add($body) } + else { throw 'unsupported response' } + + foreach ($payload in $payloads) { + $parsed = $jsonReader.DeserializeObject($payload) + if ($null -eq $parsed -or $parsed -is [array] -or $parsed.jsonrpc -cne '2.0') { throw 'invalid response' } + $responseId = Get-RpcIdText $payload + if ($null -ne $responseId) { + if (-not $idText -or $forwardedResponse -or $parsed.id -cne $rpc.id) { throw 'unexpected response id' } + if ($rpc.method -ceq 'initialize' -and $parsed.result.protocolVersion -is [string]) { + $version = $parsed.result.protocolVersion + if ($version -match '^\d{4}-\d{2}-\d{2}$') { $protocolVersion = $version } + } + $forwardedResponse = $true + } + elseif ($parsed.method -isnot [string]) { throw 'invalid notification' } + Write-ProtocolLine (Compress-JsonText $payload) + } + if ($idText -and -not $forwardedResponse) { throw 'missing response' } + } + catch { + if (-not $forwardedResponse) { + Write-RpcFailure -IdText $idText -Code -32002 -FailureCode 'transport_failed' -StateUnknown $mayHaveSent -Message 'The Quicker MCP request did not produce a complete response. Its outcome may be unknown; inspect Quicker and reopen or reread the action before retrying a write.' + } + else { [Console]::Error.WriteLine('Quicker MCP: invalid data after the completed response.') } + } + finally { + if ($null -ne $response) { $response.Dispose() } + if ($null -ne $request) { $request.Abort() } + } +} diff --git a/plugins/quicker-workbuddy/skills/write-action/SKILL.md b/plugins/quicker-workbuddy/skills/write-action/SKILL.md new file mode 100644 index 0000000..6900424 --- /dev/null +++ b/plugins/quicker-workbuddy/skills/write-action/SKILL.md @@ -0,0 +1,28 @@ +--- +name: write-action +description: Create, edit, save and preview Windows automation actions in a running Quicker through its MCP tools. Use when the user asks to write or modify a Quicker action, or consult Quicker step knowledge. Does not apply to developing the Quicker application's source code. +--- + +# Write a Quicker action + +Use the Quicker plugin's MCP tools, whose names may have a client namespace prefix. These edit Quicker's virtual workspace, not the agent repository. In particular, use Quicker's read_file, write_file, edit_file and grep for slots and @knowledge; ordinary local filesystem tools cannot resolve them. + +The live server's initialize instructions and returned capability rules describe the current authoring protocol. Read all content blocks, including attachedRules. Tool availability and current knowledge are authoritative; this plugin does not carry a duplicate module catalog. + +## Authoring workflow + +1. Load the runtime grammar using skill_load with `{ "id": "action-source" }` before editing. For an unfamiliar step, follow its steps skill: grep one keyword under @knowledge/catalog, then read the matching module YAML. Use quicker_eval with steps.resolve only for the needed branch or referenced docs. Do not invent step names or input/output keys. Host JS uses JavaScript; action `$=` expressions use Quicker's C# expression syntax. +2. For a new action use quicker_create with a concise title. To edit an existing one, use quicker_search once, identify the intended result, then quicker_open with its actionId. Opening a formal action creates an editing draft; it does not overwrite the original. +3. Keep the returned slot and actionId. Always address files explicitly as `/program.source.yaml`, `/info.yaml` or `/files/...`, and save with quicker_save `{ "path": "" }`. Several tasks can share an agent backend process and Quicker's current location; do not rely on the implicit working directory or concurrently edit the same slot. +4. Write the program in program.source.yaml; use info.yaml for title, description and appearance. data.json and info.json are Host internals. quicker_save validates and stores the draft in Quicker's 暂存区. Inspect its result and correct reported errors before reporting completion. +5. Use quicker_preview `{ "target": "" }` when showing the result helps the user. It opens Quicker's designer. Only open a browser URL actually returned by the tool; do not construct one from a designer route. + +A request to write an action normally ends with a saved draft. Promote a new draft only when the user has specified an unambiguous existing destination scene; otherwise explain the 暂存区 → 保留到… flow. Overwrite a formal action or run an action only within the user's requested scope, using quicker_overwrite or quicker_run and Quicker's approval flow. State whether the action was only saved, also previewed, or actually run. + +## Failure handling + +Check JSON-RPC errors, MCP isError, `{ok:false,code,message}`, and quicker_eval's `{error:...}` envelope. Do not infer success from receiving text. + +When a mutation times out, the connection drops, or stateUnknown is returned, inspect the relevant slot/action before retrying. If create reports programCreated with an actionId, reopen that action rather than creating another. For catalog_stale or catalog_freshness_unknown, inspect the current action and preserve pending changes; do not blindly overwrite or re-open over dirty work. + +If tools are unavailable, consult [connection.md](references/connection.md). A missing write tool usually means Quicker's 允许 MCP 写入 switch is off. The plugin must not edit server.json or clients.json to enable access, grant consent, or change approval settings. diff --git a/plugins/quicker-workbuddy/skills/write-action/references/connection.md b/plugins/quicker-workbuddy/skills/write-action/references/connection.md new file mode 100644 index 0000000..465fd6b --- /dev/null +++ b/plugins/quicker-workbuddy/skills/write-action/references/connection.md @@ -0,0 +1,18 @@ +# Connection troubleshooting + +Requires Windows PowerShell 5.1 and a Quicker build with Settings → Agent → Enable MCP. Both supported Debug and Release builds work; older releases without that setting do not. + +Run powershell.exe -NoProfile -ExecutionPolicy Bypass -File "/scripts/quicker-mcp.ps1" -Check for a redacted configuration/TCP check. This does not prove client consent or write access. + +The relay reads the current port and token from the local Quicker configuration for each request. Keep the token out of commands, client configuration, logs and conversation. It uses only loopback and does not follow proxies or redirects. + +- Missing/disabled MCP: open Quicker Settings → Agent and enable MCP. +- Connection refused: start the supported Quicker build and check the configured port. +- HTTP 401: check the running instance; token rotation is picked up on the next read. +- HTTP 403 or a first connection waiting: complete Quicker's consent UI for the actual connecting client. The relay never grants itself access. +- Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. +- A write timeout can leave an unknown outcome: inspect the slot before retrying. + +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. + +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/plugins/quicker/scripts/quicker-mcp.ps1 b/plugins/quicker/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/plugins/quicker/scripts/quicker-mcp.ps1 +++ b/plugins/quicker/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/plugins/quicker/skills/write-action/references/connection.md b/plugins/quicker/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/plugins/quicker/skills/write-action/references/connection.md +++ b/plugins/quicker/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/scripts/release-packages.json b/scripts/release-packages.json index 49cd15a..5a232a0 100644 --- a/scripts/release-packages.json +++ b/scripts/release-packages.json @@ -27,6 +27,13 @@ "mcpConfig": ".mcp.json", "marketplace": ".claude-plugin/marketplace.json" }, + { + "id": "workbuddy", + "path": "plugins/quicker-workbuddy", + "manifest": ".codebuddy-plugin/plugin.json", + "mcpConfig": ".mcp.json", + "marketplace": ".codebuddy-plugin/marketplace.json" + }, { "id": "mcp", "path": "plugins/quicker-mcp", diff --git a/shared/scripts/quicker-mcp.ps1 b/shared/scripts/quicker-mcp.ps1 index a5e57fe..f6a4e61 100644 --- a/shared/scripts/quicker-mcp.ps1 +++ b/shared/scripts/quicker-mcp.ps1 @@ -3,7 +3,7 @@ param( [string]$SettingsPath = '', [ValidateRange(1, 600)] [int]$RequestTimeoutSeconds = 180, - [ValidateSet('codex', 'cursor', 'claude', 'vscode', 'gemini', 'dsh')] + [ValidateSet('codex', 'cursor', 'claude', 'workbuddy', 'vscode', 'gemini', 'dsh')] [string]$Client = 'codex', [switch]$Check ) diff --git a/shared/skills/write-action/references/connection.md b/shared/skills/write-action/references/connection.md index 3a854e0..465fd6b 100644 --- a/shared/skills/write-action/references/connection.md +++ b/shared/skills/write-action/references/connection.md @@ -13,6 +13,6 @@ The relay reads the current port and token from the local Quicker configuration - Write tools absent: enable 允许 MCP 写入 in Quicker, keep the existing approval mode, then reconnect or start a new agent task. - A write timeout can leave an unknown outcome: inspect the slot before retrying. -After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. +After installation/update, reload the client and create a new task. Cursor IDE: Developer: Reload Window; Cursor CLI: restart agent. Claude Code: /reload-plugins or restart. WorkBuddy / CodeBuddy: /reload-plugins or restart. VS Code: MCP: List Servers → Quicker → Restart. Gemini CLI: restart. DeepSeek Harness: restart `dsh web` or the desktop app after `dsh plugin add`. -Plugins ship their own relay. Cursor and Claude expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. +Plugins ship their own relay. Cursor, Claude and WorkBuddy expand their respective plugin-root variables; Codex uses package-relative cwd. Generic MCP configuration points at the installed copy, never the development checkout. Do not edit server.json or clients.json to grant access. diff --git a/tests/test_install_clients.py b/tests/test_install_clients.py index 7cac43b..83087b5 100644 --- a/tests/test_install_clients.py +++ b/tests/test_install_clients.py @@ -20,6 +20,11 @@ def test_shared_sources_and_manifests(self): self.assertTrue((package / 'skills/write-action/SKILL.md').is_file()) market = json.loads((ROOT / ('.' + client + '-plugin') / 'marketplace.json').read_text(encoding='utf-8')) self.assertEqual((ROOT / market['plugins'][0]['source']).resolve(), package.resolve()) + workbuddy = ROOT / 'plugins/quicker-workbuddy' + self.assertEqual(json.loads((workbuddy / '.codebuddy-plugin' / 'plugin.json').read_text(encoding='utf-8'))['name'], 'quicker') + self.assertTrue((workbuddy / 'skills/write-action/SKILL.md').is_file()) + market = json.loads((ROOT / '.codebuddy-plugin' / 'marketplace.json').read_text(encoding='utf-8')) + self.assertEqual((ROOT / market['plugins'][0]['source']).resolve(), workbuddy.resolve()) dsh = json.loads((ROOT / 'plugins/quicker-dsh/package.json').read_text(encoding='utf-8')) self.assertEqual(dsh['name'], 'dsh-plugin-quicker') self.assertEqual(dsh['dsh']['bundle']['patch'], './cordis.patch.yml') @@ -114,7 +119,8 @@ def test_foreign_local_plugin_is_not_replaced(self): self.assertEqual((target / 'keep').read_text(), 'foreign') def test_each_plugin_launches_from_unrelated_directory(self): - for client, variable in [('cursor', 'CURSOR_PLUGIN_ROOT'), ('claude', 'CLAUDE_PLUGIN_ROOT'), ('dsh', None)]: + for client, variable in [('cursor', 'CURSOR_PLUGIN_ROOT'), ('claude', 'CLAUDE_PLUGIN_ROOT'), + ('workbuddy', 'CODEBUDDY_PLUGIN_ROOT'), ('dsh', None)]: with self.subTest(client=client): host = MockHost() try: