From e7d372f939a76bb4c77172ddcb991019cfbc4fd1 Mon Sep 17 00:00:00 2001 From: ringo Date: Sun, 20 Sep 2026 12:02:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(plugin):=20=E4=BA=91=E4=BB=A4=E7=89=8C?= =?UTF-8?q?=E6=94=B9=E7=94=B1=E5=90=AF=E5=8A=A8=E5=99=A8=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=EF=BC=8C=E6=B8=85=E6=8E=89=E5=BA=9F=E5=BC=83=E7=9A=84=20MCP=20?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E6=8C=87=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 症状:装好插件后调 list_projects 返回 auth_required,模型被技能里"先让用户完成 MCP 授权(codex mcp login deta_mcp)"带偏,用户卡在登录环节。 根因两条:① 启动器只透传环境变量 DETA_TOKEN,而 Finder/Dock 启动的桌面应用不继承终端环境,登录助手写的 ~/.deta 凭据根本进不去宿主进程;② 技能/README 仍留着远程形态的 OAuth 指引,本机形态里那条命令不存在。 修复:启动器按 DETA_TOKEN 环境变量 → ~/.deta/env → ~/.deta/credentials.json 顺序解析令牌并在 stderr 报告来源(不打印值);技能改为"让用户跑登录助手 → 开新会话",并明确区分 MCP 侧云令牌与面板侧 deta.city 登录;两份 README 的登录流程改为"登录一次、开新会话即可"(无需 source / launchctl / 改 .zshrc / 重启应用)。studio 0.3.1 → 0.3.2。 实测(隔离 HOME):四种取令牌路径与优先级、缺令牌时的引导文案均符合预期。 --- README.md | 8 +++---- plugins/studio/.codex-plugin/plugin.json | 2 +- plugins/studio/README.md | 11 +++++++--- plugins/studio/bin/deta-mcp.sh | 26 ++++++++++++++++++++++- plugins/studio/package-lock.json | 4 ++-- plugins/studio/package.json | 2 +- plugins/studio/skills/aml-design/SKILL.md | 16 ++++++++------ plugins/writer/README.md | 9 +++++--- plugins/writer/bin/deta-mcp.sh | 26 ++++++++++++++++++++++- 9 files changed, 81 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 5368a25..721f72f 100644 --- a/README.md +++ b/README.md @@ -81,12 +81,12 @@ codex plugin add studio@deta bash plugins/studio/bin/deta-mcp.sh ``` -装完即用,**没有 OAuth 登录步骤**。需要云侧能力时注入令牌(助手见 -`plugins/studio/README.md`「登录助手」): +装完即用,**没有 OAuth 登录步骤**。需要云侧能力(项目列表 / 项目同步 / 打开 Studio)时登录一次 +(助手用法见 `plugins/studio/README.md`「登录助手」): ```bash -node plugins/studio/bin/deta-login.mjs -source ~/.deta/env # 让 DETA_TOKEN 进入宿主进程环境 +node plugins/studio/bin/deta-login.mjs # 账号密码 / 邮箱验证码由你本人输入 +# 然后开新会话即可,无需 source / launchctl / 重启应用 ``` ## 本地迭代 diff --git a/plugins/studio/.codex-plugin/plugin.json b/plugins/studio/.codex-plugin/plugin.json index e72b47b..16142dc 100644 --- a/plugins/studio/.codex-plugin/plugin.json +++ b/plugins/studio/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "studio", - "version": "0.3.1", + "version": "0.3.2", "description": "DETA Studio 插件:以 AML 为唯一事实源编辑建筑模型,编译为建筑模型并执行规则校验。", "author": { "name": "DETA", diff --git a/plugins/studio/README.md b/plugins/studio/README.md index 3eff104..048d254 100644 --- a/plugins/studio/README.md +++ b/plugins/studio/README.md @@ -89,13 +89,18 @@ codex plugin add studio@deta bash <插件目录>/bin/deta-mcp.sh --profile studio ``` -装完即用,**没有 OAuth 登录步骤**。需要云侧能力(项目列表 / 同步)时再注入令牌: +装完即用,**没有 OAuth 登录步骤**。需要云侧能力(项目列表 / 项目同步 / 打开 Studio)时登录一次: ```bash -node bin/deta-login.mjs # 登录 deta.city,写 ~/.deta/credentials.json 与 ~/.deta/env -source ~/.deta/env # 让 DETA_TOKEN 进入宿主进程环境 +node <插件目录>/bin/deta-login.mjs # 登录 deta.city:账号密码或邮箱验证码由你本人输入 + # 写 ~/.deta/credentials.json 与 ~/.deta/env(均 0600) ``` +登录后**开新会话**(MCP 服务重新拉起时读到凭据)。启动器自己按 +`DETA_TOKEN` 环境变量 → `~/.deta/env` → `~/.deta/credentials.json` 的顺序解析令牌, +所以**不需要 source、不需要 launchctl 注入、不需要改 .zshrc、也不需要重启应用**—— +Finder/Dock 启动的宿主不继承终端环境,令牌由启动器直接读取才可靠。 + ### 登录助手(云侧能力用) ```bash diff --git a/plugins/studio/bin/deta-mcp.sh b/plugins/studio/bin/deta-mcp.sh index d46514c..c1ad240 100755 --- a/plugins/studio/bin/deta-mcp.sh +++ b/plugins/studio/bin/deta-mcp.sh @@ -68,6 +68,30 @@ export ANT_HEADLESS_WORKSPACE="$WS" # ── 工具面:产品档位缺省全量面;DETA_SURFACE 可覆盖(如 engine)── export DETA_TOOL_SURFACE="${DETA_SURFACE:-full}" -echo "[deta] 档位=${PROFILE} 运行时=${ROOT} 工作区=${WS} 工具面=${DETA_TOOL_SURFACE} 云令牌=$([ -n "${DETA_TOKEN:-}" ] && echo 已注入 || echo 未注入)" >&2 +# ── 云令牌:显式环境变量 → ~/.deta/env → ~/.deta/credentials.json ── +# 桌面应用(Finder/Dock 启动)不会继承终端的 export,也不是每个人都有 launchctl 注入, +# 因此登录助手写下的凭据必须由启动器自己解析——这是"登录一次即可用"的关键路径。 +TOKEN_SOURCE="" +if [ -n "${DETA_TOKEN:-}" ]; then + TOKEN_SOURCE="环境变量" +fi +if [ -z "${DETA_TOKEN:-}" ] && [ -f "$HOME/.deta/env" ]; then + # shellcheck disable=SC1090 + . "$HOME/.deta/env" >/dev/null 2>&1 || true + if [ -n "${DETA_TOKEN:-}" ]; then TOKEN_SOURCE="$HOME/.deta/env"; fi +fi +if [ -z "${DETA_TOKEN:-}" ] && [ -f "$HOME/.deta/credentials.json" ]; then + DETA_TOKEN="$(node -e "try{const c=JSON.parse(require('node:fs').readFileSync(process.env.HOME+'/.deta/credentials.json','utf8'));if(c&&typeof c.token==='string')process.stdout.write(c.token)}catch(e){}" 2>/dev/null || true)" + export DETA_TOKEN + if [ -n "${DETA_TOKEN:-}" ]; then TOKEN_SOURCE="$HOME/.deta/credentials.json"; fi +fi + +if [ -n "${DETA_TOKEN:-}" ]; then + CLOUD_STATE="已注入(来源=${TOKEN_SOURCE})" +else + CLOUD_STATE="未注入——云类工具将返回 auth_required:运行 bin/deta-login.mjs 登录后开新会话" +fi + +echo "[deta] 档位=${PROFILE} 运行时=${ROOT} 工作区=${WS} 工具面=${DETA_TOOL_SURFACE} 云令牌=${CLOUD_STATE}" >&2 exec node "$ENTRY" "$@" diff --git a/plugins/studio/package-lock.json b/plugins/studio/package-lock.json index 039eab5..fd14feb 100644 --- a/plugins/studio/package-lock.json +++ b/plugins/studio/package-lock.json @@ -1,12 +1,12 @@ { "name": "deta-studio-plugin", - "version": "0.3.1", + "version": "0.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "deta-studio-plugin", - "version": "0.3.1", + "version": "0.3.2", "license": "Proprietary" } } diff --git a/plugins/studio/package.json b/plugins/studio/package.json index 43767c5..79ef88a 100644 --- a/plugins/studio/package.json +++ b/plugins/studio/package.json @@ -1,6 +1,6 @@ { "name": "deta-studio-plugin", - "version": "0.3.1", + "version": "0.3.2", "description": "DETA Studio:AML 建筑模型读写与编译校验(Codex 插件 / dsh 组合包 双壳)", "type": "module", "license": "Proprietary", diff --git a/plugins/studio/skills/aml-design/SKILL.md b/plugins/studio/skills/aml-design/SKILL.md index 2f4518d..31fe85c 100644 --- a/plugins/studio/skills/aml-design/SKILL.md +++ b/plugins/studio/skills/aml-design/SKILL.md @@ -111,7 +111,10 @@ Studio 就是deta.city 上的建筑性能应用。在 Codex 右侧内置浏览 deta.city 登录并跳到 Studio。 - 典型节奏:`open_studio()` 拿 `url` → 面板打开 → `open_studio({ waitSeconds: 20 })` 确认 `executor_online: true` → 再调 `simulate` / `studio_command` 等执行器侧工具。 - - 若返回 `auth_required` → 先让用户完成 MCP 授权(`codex mcp login deta_mcp`)再重试; + - 若返回 `auth_required` → 云令牌未注入(**本机形态没有 MCP 授权,不要去找 `codex mcp login`**): + 让用户在终端运行插件自带登录助手 `node <插件目录>/bin/deta-login.mjs`(账号与密码/验证码由用户 + 本人输入;助手写 `~/.deta/credentials.json` 与 `~/.deta/env`,启动器会自动读取——不需 source、 + 不需 launchctl、不需重启应用),随后**开新会话**重试; 若 `url` 报「票据无效或已过期」→ 重新调一次,不要改成手工登录。 2. 按 browser 插件技能(`control-in-app-browser`)的 Bootstrap 初始化,再取内置浏览器句柄: `const iab = await agent.browsers.get("iab");`,并先读一次 `await iab.documentation()`。 @@ -137,12 +140,11 @@ Studio 就是deta.city 上的建筑性能应用。在 Codex 右侧内置浏览 `open_studio` 时才退化为手工:在面板里打开 `https://deta.city/login` 完成一次登录 (登录态写入该浏览器的 `ant_token` cookie 与 `ant-model-auth` localStorage,之后长期有效), 登录完成后重新打开 `studioUrl` 即自动加载项目。 -- **宿主把 MCP 授权页开在哪个浏览器由宿主决定**(实测 Codex Desktop 走系统默认浏览器), - 且**那一页的登录态不会进入面板**——所以别把"MCP 已授权"当成"面板已登录",两者要分别确认: - MCP 授权只解决 Codex↔服务端;面板登录解决 Studio 在面板里的会话(`open_studio` 正是两者的桥)。 - 实测口径:授权页在系统浏览器完成换码后停留在宿主的回调页("Authentication complete. You may close - this window."),该页不归我们控制;授权页自身已改为**在隐藏框架内完成换码**并给出「打开 deta.city」 - 与「关闭本页」,不再顶层跳走。 +- **本机形态没有 MCP 授权**(进程在本机由宿主拉起,无 OAuth、无 401、无令牌续期),要分清的是两件事: + - **MCP 侧的云令牌**:只影响项目列表 / 项目同步 / `open_studio` 这类云工具,`auth_required` 的处置见上; + - **面板侧的 deta.city 登录**:靠 `open_studio` 的一次性链接自动完成,登录态写在该浏览器的 + `ant_token` cookie 与 `ant-model-auth` localStorage,之后长期有效。 + 两者互不替代——拿到云令牌不等于面板已登录,反之亦然。 - 没有 `projectId`:Studio 打开的是空项目。先在门户创建云项目拿到 ID,再 `push_project(…, projectId)` 绑定。 - 宿主没有内置浏览器(CLI 等形态):直接把 `studioUrl` 给用户,让他自己打开,不要假装已经打开。 diff --git a/plugins/writer/README.md b/plugins/writer/README.md index febbfe4..c8c19fa 100644 --- a/plugins/writer/README.md +++ b/plugins/writer/README.md @@ -50,13 +50,16 @@ codex plugin add writer@deta bash <插件目录>/bin/deta-mcp.sh --profile writer ``` -需要云侧能力(项目列表 / 同步)时注入令牌: +需要云侧能力(项目列表 / 项目同步 / 打开 Studio)时登录一次: ```bash -node bin/deta-login.mjs # 登录 deta.city,写 ~/.deta/credentials.json 与 ~/.deta/env -source ~/.deta/env # 让 DETA_TOKEN 进入宿主进程环境 +node <插件目录>/bin/deta-login.mjs # 账号密码 / 邮箱验证码由你本人输入 + # 写 ~/.deta/credentials.json 与 ~/.deta/env(均 0600) ``` +登录后**开新会话**即可——启动器自己按 `DETA_TOKEN` 环境变量 → `~/.deta/env` → +`~/.deta/credentials.json` 的顺序解析令牌,不需要 source、不需要 launchctl、不需要重启应用。 + ## 安装(dsh) ```bash diff --git a/plugins/writer/bin/deta-mcp.sh b/plugins/writer/bin/deta-mcp.sh index 1a780ad..22ef3ca 100755 --- a/plugins/writer/bin/deta-mcp.sh +++ b/plugins/writer/bin/deta-mcp.sh @@ -68,6 +68,30 @@ export ANT_HEADLESS_WORKSPACE="$WS" # ── 工具面:产品档位缺省全量面;DETA_SURFACE 可覆盖(如 engine)── export DETA_TOOL_SURFACE="${DETA_SURFACE:-full}" -echo "[deta] 档位=${PROFILE} 运行时=${ROOT} 工作区=${WS} 工具面=${DETA_TOOL_SURFACE} 云令牌=$([ -n "${DETA_TOKEN:-}" ] && echo 已注入 || echo 未注入)" >&2 +# ── 云令牌:显式环境变量 → ~/.deta/env → ~/.deta/credentials.json ── +# 桌面应用(Finder/Dock 启动)不会继承终端的 export,也不是每个人都有 launchctl 注入, +# 因此登录助手写下的凭据必须由启动器自己解析——这是"登录一次即可用"的关键路径。 +TOKEN_SOURCE="" +if [ -n "${DETA_TOKEN:-}" ]; then + TOKEN_SOURCE="环境变量" +fi +if [ -z "${DETA_TOKEN:-}" ] && [ -f "$HOME/.deta/env" ]; then + # shellcheck disable=SC1090 + . "$HOME/.deta/env" >/dev/null 2>&1 || true + if [ -n "${DETA_TOKEN:-}" ]; then TOKEN_SOURCE="$HOME/.deta/env"; fi +fi +if [ -z "${DETA_TOKEN:-}" ] && [ -f "$HOME/.deta/credentials.json" ]; then + DETA_TOKEN="$(node -e "try{const c=JSON.parse(require('node:fs').readFileSync(process.env.HOME+'/.deta/credentials.json','utf8'));if(c&&typeof c.token==='string')process.stdout.write(c.token)}catch(e){}" 2>/dev/null || true)" + export DETA_TOKEN + if [ -n "${DETA_TOKEN:-}" ]; then TOKEN_SOURCE="$HOME/.deta/credentials.json"; fi +fi + +if [ -n "${DETA_TOKEN:-}" ]; then + CLOUD_STATE="已注入(来源=${TOKEN_SOURCE})" +else + CLOUD_STATE="未注入——云类工具将返回 auth_required:运行 bin/deta-login.mjs 登录后开新会话" +fi + +echo "[deta] 档位=${PROFILE} 运行时=${ROOT} 工作区=${WS} 工具面=${DETA_TOOL_SURFACE} 云令牌=${CLOUD_STATE}" >&2 exec node "$ENTRY" "$@"