# DETA Studio 插件(Codex 插件 / dsh 组合包) DETA 领域能力(AML 建筑模型读写、编译校验、围护结构统计、空间邻接查询) 以**本机 MCP 服务**形态挂进 Agent harness:同一个目录既是 Codex 插件根, 也是 dsh 组合包根,两端共享 `skills/` 与**同一个启动器**。 - 发行标识:**`studio@deta`**(插件 `studio` + 市场 `deta`) - MCP 服务名:**`studio_mcp`**(工具前缀 `mcp__studio_mcp__…`) - 产品档位:启动器 `--profile studio`(工作区缺省 `~/.deta/studio/workspace`) ## 连接形态与凭据(唯一管道:本机 stdio) | 项 | 值 | |----|-----| | 形态 | **本机 stdio**:宿主拉起 `bin/deta-mcp.sh --profile studio`,由它解析领域服务运行时与工作目录 | | MCP 服务名 | `studio_mcp`(工具前缀 `mcp__studio_mcp__…`);其他产品用各自服务名,可同时安装 | | 宿主声明 | Codex 读 `.mcp.json`;dsh 读 `cordis.patch.yml`——两边都只声明"调用同一个脚本、带哪个档位" | | 工作目录 | `DETA_WORKSPACE` → `ANT_HEADLESS_WORKSPACE` → 缺省 `~/.deta/studio/workspace`(启动器创建并在 stderr 回显) | | 运行时 | `DETA_SERVER_ROOT` → `~/.deta/runtime` → 本机开发检出(回落到开发检出时启动器打印提示) | | 云侧能力(可选) | `DETA_TOKEN`(`node bin/deta-login.mjs` 获取):项目/楼栋列表、`push_project` / `pull_project` | | Studio 执行器中继(可选) | `ANT_WORKSPACE_BRIDGE_URL` + 项目 ID(三要素齐备才启用;供模拟/画布类工具) | **本机形态不做 MCP 鉴权**(进程由宿主或用户在本机拉起,没有 OAuth、没有 401、没有令牌续期)。 未注入 `DETA_TOKEN` 时,云类工具返回 `auth_required`,其余工具(编辑、编译、校验、统计、 脚本、模拟)照常工作——这是与远程形态**同一份工具实现**的不同输入,不是两套代码。 ## 工具面:编辑归宿主,MCP 只做引擎与同步 AML 是纯文本 DSL,读写、搜索、重构一律由**宿主原生的文件工具**完成 (Codex 的 read / patch / grep / shell;dsh 的同名能力),MCP 不是编辑入口: | 分工 | 谁做 | |------|------| | 读取 / 修改 / 搜索 `aml.xml`、`bss.md`、`rules.yml`、`behaviors.yml`、`design-brief.md` | 宿主原生工具(本地项目目录里的文件) | | 编译、规范校验、规则检查、围护结构统计、空间邻接、领域脚本 | MCP 引擎工具(编译 / 校验 / 统计 / 邻接 / 脚本等) | | 改动送进引擎工作区、取回工作区 | MCP 同步工具 | 本机形态为**全量工具面**(含工作区文件类工具)。**当前可用的完整工具名以运行时 `list_capabilities` 为准**,本仓文档不列举工具清单。 ## 本地项目目录约定 一个 DETA 项目就是一个普通目录;引擎工具读的是**引擎工作区**,因此改动要先同步: ``` my-project/ ├── deta.json # 可选:项目绑定({ "projectId": "...", "name": "..." }) ├── aml.xml # 必需:建筑模型唯一事实源 ├── bss.md # 可选:样式/构造附属文档 ├── rules.yml # 可选:校验规则 ├── behaviors.yml # 可选:声明式行为规则 └── design-brief.md # 可选:设计任务书 ``` - 想让引擎直接以项目目录为工作区:启动宿主前设 `DETA_WORKSPACE=<项目目录>`。 - `deta.json` 里的 `projectId` 是 deta.city 云项目 ID;带上它的同步调用会把同一个 ID 绑定到引擎工作区,之后生成/拉取会带同一个 Studio 深链 `https://deta.city/design/`。 - 文件名沿用引擎侧约定(`aml` ↔ `aml.xml`、`brief` ↔ `design-brief.md` 等), 本地目录与引擎工作区结构一致,拉取结果可直接落盘回本地目录。 ## 端到端工作流:本地编辑 → 同步 → 校验 → Studio 查看 ```text 1. 本地编辑 read/patch/grep 直接改 aml.xml(MCP 不参与编辑) 2. 同步 把改动送进引擎工作区(带 projectId 时同时绑定云项目) → { ok, files, projectId, studioUrl: "https://deta.city/design/" } 3. 引擎校验 编译 AML 为建筑模型(工作区最新版本)→ 语法/几何/规则校验逐条修复 围护结构统计与空间邻接查询按需调用 4. Studio 查看 在宿主内置浏览器面板打开 studioUrl;已有相同 URL 的标签优先复用, 不为同一项目重复开新标签,也不要 goto 重载已有标签 5. 跑模拟 在面板里的 Studio 界面运行——模拟由 Studio 执行,本插件 MCP 不替代它 6. 反向核对 从引擎工作区拉回文件(工作区为空时返回空集) ``` 路径安全:同步只接受工作区相对路径,绝对路径与 `..` 穿越会被拒绝,单次载荷上限 1 MiB。 ## 安装(Codex) ```bash # 1. 添加市场并安装插件 codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git codex plugin add studio@deta # 2. 准备领域服务运行时(二选一) # a) 本机引擎包已安装 → 启动器自动找到(~/.deta/runtime) # b) 从源码构建:在领域服务仓库执行 npm run build:mcp,并让 DETA_SERVER_ROOT 指向它 # # 冒烟(应等待 stdin/stdout): bash <插件目录>/bin/deta-mcp.sh --profile studio ``` 装完即用,**没有 OAuth 登录步骤、也不需要终端**。需要云侧能力(项目列表 / 新建项目 / 项目同步 / 打开 Studio)时: ``` 在对话里说"登录"或直接让助手新建项目/上传到云 —— 助手会调 login 工具给出一个授权地址, 你在浏览器打开(首次输一次账号密码或邮箱验证码)→ 点「登录并授权」→ 完成。 令牌自动写入 ~/.deta 并即时生效;凭据过期时先用 refresh token 静默续期,用户无感。 ``` 命令行形态(无 `login` 工具时)的兜底做法: ```bash ~/.deta/bin/deta login # 由启动器自动注册;账号密码或 --email-code <邮箱> ~/.deta/bin/deta doctor # 端到端自检:运行时、凭据、GSA、MCP 握手 ``` 启动器按 `DETA_TOKEN` 环境变量 → `~/.deta/env` → `~/.deta/credentials.json` 的顺序解析令牌, 所以浏览器授权后的下一次会话也自动带着登录态——不需要 source、不需要 launchctl、不需要重启应用。 ### 登录助手(云侧能力用) ```bash node bin/deta-login.mjs # 交互式:读标识与密码,写 ~/.deta/* node bin/deta-login.mjs -u <用户名|已验证邮箱|已验证手机号> # 免交互输入标识 node bin/deta-login.mjs --email-code <邮箱> # 邮箱验证码登录(未设密码的账号用) node bin/deta-login.mjs --base-url https:// # 自建/预发环境 ``` **标识(identifier)填门户登录页上用的那一个**:用户名、已验证邮箱、已验证手机号,服务端都会解析到同一账号。 助手先匿名调用 `/login/check` 预检标识是否已注册,再走 `/login` 做密码校验(不走门户的「登录即注册」端点, 不会误建账号)。失败时按服务端提示给出下一步: | 服务端提示 | 含义与处理 | |------------|------------| | `该标识在 未注册` | 标识不是门户上用的那一个;邮箱验证码注册的账号标识填邮箱 | | `用户不存在/密码错误` | 服务端不区分「账号不存在」与「密码不匹配」;已确认标识存在,即密码不符,或改用 `--email-code` | | `该邮箱/手机号尚未验证…` | 先用验证码方式登录一次门户完成验证 | | `该登录方式未开放` | 用 `GET /prod-api/login/methods` 查当前启用项 | ## 安装(dsh) ```bash export DETA_PLUGIN_ROOT=<本包所在目录> # 配置层按它定位启动器 export DETA_WORKSPACE=<你的项目目录> # 可选;缺省 ~/.deta/workspace dsh plugin --profile add <本包> ``` `cordis.patch.yml` 声明本机 stdio,经 `bash -lc` 调用同一个 `bin/deta-mcp.sh`; 未设置 `DETA_PLUGIN_ROOT` 时启动器明确报错退出,不会静默失败。 ## 文件 ``` .codex-plugin/plugin.json Codex 插件清单 .mcp.json Codex MCP 声明(stdio → ./bin/deta-mcp.sh) package.json dsh 组合包声明(dsh.bundle.patch) cordis.patch.yml dsh 配置层(同一启动器,stdio) bin/deta-login.mjs 登录助手(写 ~/.deta/credentials.json + ~/.deta/env,供云侧能力用) bin/deta-mcp.sh 本机 stdio 启动器(两宿主共用;解析运行时与工作目录) README.md 本文件(安装 / 连接 / 排障) skills/aml-design/SKILL.md 宿主侧技能(工具使用规则;不含工具清单) ``` ## 已知缺陷(实测,2026-09-10) **上游:编码代理 × 模型服务 命名空间重复** 会话累积较多本插件工具调用后,代理会在请求里重复声明 MCP 命名空间,模型服务的 Responses 兼容层拒绝请求: ``` Duplicate namespace name 'deta'; Namespace names must be unique. ``` 复现记录(同一插件、不同会话长度): | 代理版本 | 会话规模 | 触发位置 | |---------|---------|---------| | 0.144.4 | 一步并发 2 次调用 | input[10]、input[18] | | 0.144.4 | 串行 7–8 次调用 | input[37]、input[47] | | 0.154.0 | 短会话 5 工具 | 未触发 | | 0.154.0 | 长会话(≈15+ 工具) | input[260] | 已排除/无效的手段:`wire_api = "chat"`(该版本已移除,仅支持 responses)、 `features.non_prefixed_mcp_tool_names`(仅去掉命名空间前缀,重复依旧)、 `supports_parallel_tool_calls = false`(削弱并发触发面,长会话仍复现)。 **应对**:完成一个任务后另起会话;撞到该错误不要重试,重开会话即可(工作区文件保留)。 ## 已修缺陷(实测) | 现象 | 根因 | 修复 | |------|------|------| | 写类工具返回 `user cancelled MCP tool call` | MCP 工具默认需审批,非交互模式下无法弹窗 | `.mcp.json` 声明 `default_tools_approval_mode: "approve"`(实测 `auto`/`writes` 都会被取消,只有 `approve` 放行) | | 本机 stdio 形态起不来:`ERR_UNSUPPORTED_DIR_IMPORT` | 启动器指向未打包的产物,依赖包的目录 import 在 Node ESM 下非法 | 领域服务提供打包入口;启动器优先取打包产物,回落未打包产物时打印警告 | | 一个插件两种形态并存(远程 URL + 本机 stdio) | 历史遗留:远程端点声明与本地启动器同时存在,语义冲突 | 统一为**本机 stdio 单一管道**,远程端点声明从插件移除 |