# DETA — Agent Plugins DETA 领域能力在各类 Agent harness 上的分发仓:**品牌 = 市场,产品 = 插件,一个仓承载多产品**。 | 宿主 | 形态 | 安装 | |------|------|------| | Codex | 插件(`.codex-plugin/plugin.json` + `skills/` + `.mcp.json`);本仓同时是 Codex 插件市场 `deta` | `codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git` → `codex plugin add studio@deta` | | dsh (deepseek-harness) | 组合包 bundle(`dsh.bundle.patch` + `cordis.patch.yml`) | `dsh plugin --profile add ./plugins/studio` | 发行标识(Codex 语法 = 插件@市场):**`studio@deta`**、**`writer@deta`**——两个插件互不冲突, 可同时安装(MCP 服务名 `studio_mcp` / `writer_mcp`,工作区各自独立)。新增产品按同一结构落位: `plugins/<产品>/` 自带 `.codex-plugin/plugin.json`、`.mcp.json`、`package.json`、`cordis.patch.yml`、 `bin/`、`skills/`、`README.md`,市场 `plugins` 数组加一条即可。 能力本体(AML 建筑模型读写、编译校验、围护结构统计、空间邻接查询)以 **MCP 服务**提供, 运行时在**本机**解析(引擎包 / 源码构建),宿主侧只声明"用哪个启动器"; 同一份后端、同一个启动器、同一套技能被所有宿主复用,新增宿主只需再加一层声明式壳。 ## 职责边界(仓库章程) 本仓是**宿主适配与分发层,零逻辑、不承载契约**。三条铁律: | 问题 | 归属 | 内容 | |------|------|------| | 能力在哪 | **ant-copilot**(唯一来源) | 工具实现、MCP 协议层、启动形态(本机 stdio / 服务端 HTTP)、工具面裁剪、领域技能 | | 怎么被发现和启动 | **本仓** | 宿主清单(`.codex-plugin/plugin.json`、`cordis.patch.yml`)、连接声明(`.mcp.json`)、启动器、宿主侧技能投影 | | 怎么在云上跑 | **infra** | 部署 / 证书 / 路由 / 重启;云端只跑 ant-copilot 的构建产物 | 因此本仓**不做**这些事(由 `scripts/check-plugin-contract.mjs` 在 CI 强制): - 不在文档或技能里列**工具清单 / 工具一览**——工具面按部署形态裁剪,清单必然过期; 取清单的唯一途径是运行时调用 `list_capabilities`(技能必须给出这条指引)。 - 不解释 ant-copilot 的内部常量与实现路径(`DETA_TOOL_SURFACE`、`dist/…` 等)。 - 不把「开发检出路径」当作运行前提——启动器应随包解析运行时(当前仍保留开发检出回落, 校验脚本以 warning 提示,本机引擎包落地后升级为 error)。 - 市场条目与实际插件目录**必须一致**(条目 `name` = 插件清单 `name`、`path` 真实存在), 由校验脚本的 E4 规则强制——改名或加产品时不会留下悬空条目。 **衡量标准**:新增一个工具需要改几处?目标是 **1 处**(ant-copilot 注册工具, 能力目录与文档自动派生),本仓零改动。 ## 连接形态(唯一管道:本机 stdio) ``` 宿主(Codex / dsh) └─ 拉起 plugins/<产品>/bin/deta-mcp.sh --profile <产品> ← 各产品带自己的档位,脚本同一份 ├─ 解析领域服务运行时:DETA_SERVER_ROOT → ~/.deta/runtime → 本机开发检出 ├─ 解析工作目录:DETA_WORKSPACE → ANT_HEADLESS_WORKSPACE → ~/.deta/<产品>/workspace └─ 执行领域服务运行时入口(打包产物;回落未打包产物时打印警告) └─ MCP stdio:全量工具面;无 OAuth、无 401、无令牌续期 ``` - **本机形态不做 MCP 鉴权**:进程在本机由宿主或用户拉起,天然可信。 - 云侧能力(项目/楼栋列表、同步)是**可选的输入**:注入 `DETA_TOKEN` 即有,缺省时云类工具 返回 `auth_required`,其余工具照常——同一份工具实现,不是两套分支。 - Studio 执行器中继(模拟/画布)需 `ANT_WORKSPACE_BRIDGE_URL` + 项目 ID 三要素齐备。 - **各产品独立命名空间**:MCP 服务名 `studio_mcp` / `writer_mcp`(工具前缀 `mcp__<服务名>__<工具>`),两个插件可同时安装互不冲突;产品间不共享工作区。 - 服务端仍保留 HTTP 形态的服务(数据面/其他客户端用),但它**不是本插件声明的连接形态**; 插件的连接声明只有本机 stdio 一种。 ## 内容 | 插件 | 服务名 | 技能 | 能力 | 依赖 | |------|--------|------|------|------| | `studio@deta` | `studio_mcp` | `studio:aml-design` | AML 建筑模型读写、编译与校验、围护结构统计、空间邻接查询 | node;领域服务运行时(本机引擎包或源码构建) | | `writer@deta` | `writer_mcp` | `writer:report-authoring` | 报告/文档产出:读模型、取数据(统计/分析/模拟缓存/气象/规范)、成文 | 同上 | ## 安装(Codex) ```bash # 从 Git(分发用) codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git codex plugin list codex plugin add studio@deta ``` 领域服务运行时随插件包分发,启动器首次拉起时自动安装到 `~/.deta/runtime`,插件升级后自动同步 (只比对哈希,命中就跳过)。需要显式重装、或补装候选预览图的栅格化依赖时: ```bash ~/.deta/bin/deta install-runtime # 安装/更新运行时 + 预览图依赖,并立刻做一次真实 MCP 握手 ~/.deta/bin/deta status # 运行时来源(版本 / 提交 / 哈希)、凭据来源、工作区 ~/.deta/bin/deta doctor # 端到端自检:运行时 / 凭据 / 编译服务 / MCP 握手 ``` **装完即用**:没有额外安装步骤,也不需要终端。需要云侧能力(项目列表 / 新建项目 / 项目同步 / 打开 Studio)时:让助手调 `login` 工具 → 浏览器打开授权地址(首次输一次账号密码或邮箱验证码)→ 点「登录并授权」;令牌自动写入 `~/.deta` 并即时生效,过期先静默续期。 命令行形态(无 `login` 工具)的兜底及排查(助手用法见 `plugins/studio/README.md`): ```bash ~/.deta/bin/deta login # 由启动器自动注册;账号密码或 --email-code <邮箱> ~/.deta/bin/deta doctor # 自检:运行时 / 凭据 / GSA / MCP 握手 ``` ## 本地迭代 插件内容改动后 Codex 不会自动感知,按官方流程打 cachebuster 版本号再重装: ```bash python3.11 ~/.codex/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py \ ~/Dev/ant/deta-agent-plugins/plugins/studio codex plugin add studio@deta ``` (版本号形如 `0.1.0+codex.20260910020424`;重装后需开新会话才能加载新技能。) 开发态要跑**工作树**(而不是插件包里那份打包运行时)时,显式指定运行时根: ```bash DETA_SERVER_ROOT=<领域服务仓库所在路径> bash plugins/studio/bin/deta-mcp.sh --profile studio ``` 领域服务改动后,要把新产物同步进插件包(否则同事与你自己装的都是旧运行时), 并顺手升插件版本(契约校验会拦下版本与运行时不一致的情况): ```bash node scripts/sync-runtime.mjs node scripts/check-plugin-contract.mjs bash scripts/verify-runtime-provision.sh # 运行时供给探针(全新 HOME 下 10 项断言) ``` 校验清单: ```bash python3.11 ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py \ ~/Dev/ant/deta-agent-plugins/plugins/studio node scripts/check-plugin-contract.mjs # 本仓章程校验(CI 同款) codex plugin marketplace list codex mcp list | grep -i studio # 应显示 stdio 形态(Command 列)与 studio_mcp ``` ## 双壳架构(Codex + dsh 同一产物) `plugins/studio/` 这一个目录同时是 Codex 插件根与 dsh 组合包根,共享核心、各带一层薄壳: | 组成 | 文件 | Codex | dsh | |------|------|-------|-----| | 插件清单 | `.codex-plugin/plugin.json`(`name` = 产品名) | ✅ 使用 | — | | MCP 声明 | `.mcp.json`(stdio → `bin/deta-mcp.sh --profile <产品>`,`serverName` = `<产品>_mcp`) | ✅ 使用(可放 Codex 私有键) | — | | 组合包声明 | `package.json`(`dsh.bundle.patch`) | 忽略 | ✅ 使用 | | 配置层 | `cordis.patch.yml`(同一启动器,stdio,`serverName` = `<产品>_mcp`) | 忽略 | ✅ 使用 | | 宿主侧技能 | `skills/aml-design/SKILL.md` | ✅ 共享 | ✅ 共享 | | 启动器 | `bin/deta-mcp.sh` | ✅ 每产品一份(同一实现,产品差异走 `--profile`) | ✅ | 共享面(两端一致,零适配): - **技能文件格式**:`/SKILL.md` + frontmatter 必填 `name`/`description`,kebab-case。 Codex 与 dsh(`@deepseek-ai/dsh-skill-filesystem`)要求相同。 - **共享技能根**:两端都扫描 `~/.agents/skills/` 与 `<项目>/.agents/skills/` (dsh 侧为 rank 500 / 200 的发现根,且显式支持 `/skills`)。 - **MCP 工具命名**:两端同为 `mcp____`,我们统一 `serverName = deta`。 各自不同的部分(不共享): - MCP 的声明位置不同(Codex 读 `.mcp.json`,dsh 读 `cordis.patch.yml` 的 mcp-client 行), 但**都指向同一个启动器**。 - Codex 私有键(`default_tools_approval_mode`、`omit_tools_from`)只写在 `.mcp.json`。 - 分发渠道不同:Codex 走 git 市场,dsh 走 npm / git / tarball。 ### dsh 侧安装与验证 ```bash export DETA_PLUGIN_ROOT=~/Dev/ant/deta-agent-plugins/plugins/studio dsh plugin --profile add "$DETA_PLUGIN_ROOT" # 只验证配置层是否合并正确(不启动、不需凭据) cd ~/Dev/ant/deepseek-harness node apps/cli/lib/bin.js --profile headless --dump-config \ --patch "$DETA_PLUGIN_ROOT/cordis.patch.yml" # 输出中应出现 `# == .../plugins/studio/cordis.patch.yml` 与 deta-mcp(transport: stdio) ``` ## 已知缺陷(实测) **上游:编码代理 × 模型服务 命名空间重复** —— 会话累积较多本插件工具调用后,代理会在请求里 重复声明 MCP 命名空间,模型服务的 Responses 兼容层拒绝并报 `Duplicate namespace name 'deta'; Namespace names must be unique.`。 应对:完成一个任务后另起会话;撞到该错误不要重试(工作区文件保留)。 复现记录与已排除手段见 `plugins/studio/README.md`。 ## 已修缺陷(实测) | 现象 | 根因 | 修复 | |------|------|------| | 写类工具返回 `user cancelled MCP tool call` | MCP 工具默认需审批,非交互模式无法弹窗 | `.mcp.json` 声明 `default_tools_approval_mode: "approve"` | | 本机 stdio 形态起不来:`ERR_UNSUPPORTED_DIR_IMPORT` | 启动器指向未打包的产物(依赖包目录 import 在 Node ESM 下非法) | 领域服务提供打包入口;启动器优先取打包产物,回落未打包产物时打印警告 | | 一个插件两种形态并存(远程 URL + 本机 stdio) | 历史遗留,语义冲突 | 统一为本机 stdio 单一管道 | | 启动器把开发检出当唯一运行前提 | 默认值写死开发检出路径 | 运行时按 `DETA_SERVER_ROOT → ~/.deta/runtime → 开发检出` 解析,回落时打印提示 | ## 目录结构 ``` .agents/plugins/marketplace.json # Codex 默认市场(ChatGPT 登录用户) .agents/plugins/api_marketplace.json # Codex API key 登录用户市场 .gitea/workflows/ci.yml # CI:跑 scripts/check-plugin-contract.mjs scripts/check-plugin-contract.mjs # 仓库章程校验(工具清单 / 内部实现 / 开发检出依赖) plugins/studio/ # 产品插件:同一目录 = Codex 插件根 = dsh 组合包根 ├── .codex-plugin/plugin.json # Codex 插件清单(name: studio) ├── .mcp.json # Codex MCP 声明(studio_mcp → ./bin/deta-mcp.sh --profile studio) ├── package.json # dsh 组合包声明(dsh.bundle.patch) ├── cordis.patch.yml # dsh 配置层(同一启动器,serverName: studio_mcp) ├── bin/deta-login.mjs # 登录助手(~/.deta/credentials.json + ~/.deta/env) ├── bin/deta-mcp.sh # 本机 stdio 启动器(多产品共用;--profile 区分档位) ├── README.md # 插件说明(连接形态 / 凭据 / 排障) └── skills/aml-design/SKILL.md # 宿主侧技能(不含工具清单) plugins/writer/ # 产品插件:报告/文档产出 ├── .codex-plugin/plugin.json # Codex 插件清单(name: writer) ├── .mcp.json # Codex MCP 声明(writer_mcp → ./bin/deta-mcp.sh --profile writer) ├── package.json # dsh 组合包声明(dsh.bundle.patch) ├── cordis.patch.yml # dsh 配置层(同一启动器,serverName: writer_mcp) ├── bin/deta-login.mjs # 登录助手(云侧能力用) ├── bin/deta-mcp.sh # 本机 stdio 启动器(同一实现;缺省档位 writer) ├── README.md # 插件说明(连接形态 / 能力边界 / 排障) └── skills/report-authoring/SKILL.md # 宿主侧技能(报告取数与纪律) ```