112 lines
5.1 KiB
Bash
Executable File
112 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# DETA 产品插件的本机 MCP stdio 启动器(唯一入口,多产品共用)
|
||
#
|
||
# 两个宿主(Codex 插件 / dsh 组合包)都通过本脚本拉起同一个领域服务;
|
||
# 产品差异只由 --profile 决定(工作区默认位置、工具面),宿主侧只声明"调哪个脚本、带哪个档位"。
|
||
#
|
||
# 用法:deta-mcp.sh [--profile <studio|writer>]
|
||
#
|
||
# 依赖:node + 已构建的领域服务运行时
|
||
#
|
||
# 环境变量:
|
||
# DETA_SERVER_ROOT 领域服务运行时根目录(未设时自动查找,见下)
|
||
# DETA_WORKSPACE AML 工作目录(引擎侧工作区真值;缺省 ~/.deta/<profile>/workspace)
|
||
# ANT_HEADLESS_WORKSPACE 同上(兼容旧名,DETA_WORKSPACE 优先)
|
||
# DETA_TOKEN deta.city 门户令牌(可选;不注入则云类工具返回 auth_required)
|
||
# ANT_WORKSPACE_BRIDGE_URL 网关基址(可选;与项目 ID 一起启用 Studio 执行器中继)
|
||
# DETA_SURFACE 工具面覆盖(缺省 full)
|
||
set -euo pipefail
|
||
|
||
# ── 产品档位:宿主在声明里传 --profile;缺省 studio ──
|
||
PROFILE="${DETA_PROFILE:-writer}"
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--profile) PROFILE="${2:?--profile 需要一个值}"; shift 2 ;;
|
||
*) break ;;
|
||
esac
|
||
done
|
||
|
||
# ── 运行时解析:显式 DETA_SERVER_ROOT → 本机引擎包安装位置 → 本机开发检出(打印提示)──
|
||
ROOT="${DETA_SERVER_ROOT:-}"
|
||
if [ -z "$ROOT" ]; then
|
||
for cand in "$HOME/.deta/runtime" "$HOME/Dev/ant/ant-copilot"; do
|
||
if [ -f "$cand/dist/deta-mcp.mjs" ] || [ -f "$cand/dist/src/headless/mcp-server.js" ]; then ROOT="$cand"; break; fi
|
||
done
|
||
fi
|
||
|
||
if ! command -v node >/dev/null 2>&1; then
|
||
echo "[deta] 未找到 node,请先安装 Node.js" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 入口优先取 esbuild 打包形态:tsc 产物在 Node ESM 下会因依赖包的目录 import 直接失败
|
||
ENTRY=""
|
||
if [ -n "$ROOT" ]; then
|
||
if [ -f "$ROOT/dist/deta-mcp.mjs" ]; then
|
||
ENTRY="$ROOT/dist/deta-mcp.mjs"
|
||
elif [ -f "$ROOT/dist/src/headless/mcp-server.js" ]; then
|
||
ENTRY="$ROOT/dist/src/headless/mcp-server.js"
|
||
echo "[deta] 警告:回落到未打包产物,请先在该运行时目录执行 npm run build:mcp" >&2
|
||
fi
|
||
fi
|
||
|
||
if [ -z "$ENTRY" ]; then
|
||
echo "[deta] 未找到领域服务运行时(已尝试:DETA_SERVER_ROOT、\$HOME/.deta/runtime、\$HOME/Dev/ant/ant-copilot)" >&2
|
||
echo "[deta] 请安装本机引擎包,或设置 DETA_SERVER_ROOT 指向已构建的领域服务仓库" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [ "$ROOT" = "$HOME/Dev/ant/ant-copilot" ]; then
|
||
echo "[deta] 提示:使用本机开发检出 ${ROOT}(非打包运行时)" >&2
|
||
fi
|
||
|
||
# ── 工作目录:宿主不会传项目目录(cwd 通常是插件根),按产品档位定稳定位置 ──
|
||
WS="${DETA_WORKSPACE:-${ANT_HEADLESS_WORKSPACE:-$HOME/.deta/$PROFILE/workspace}}"
|
||
mkdir -p "$WS"
|
||
export ANT_HEADLESS_WORKSPACE="$WS"
|
||
|
||
# ── 工具面:产品档位缺省全量面;DETA_SURFACE 可覆盖(如 engine)──
|
||
export DETA_TOOL_SURFACE="${DETA_SURFACE:-full}"
|
||
|
||
# ── 稳定入口:把命令行门面注册为 ~/.deta/bin/deta(幂等,路径随插件更新自动刷新)──
|
||
# 插件装在宿主缓存目录,用户看不见这个路径;而用户与工具回执都需要一条可复制的命令。
|
||
PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||
BIN_DIR="$HOME/.deta/bin"
|
||
SHIM="$BIN_DIR/deta"
|
||
SHIM_BODY="#!/bin/sh
|
||
# DETA 命令行门面(由插件启动器自动维护,勿手工编辑)
|
||
exec \"$(command -v node)\" \"$PLUGIN_ROOT/bin/deta-cli.mjs\" \"\$@\"
|
||
"
|
||
mkdir -p "$BIN_DIR" 2>/dev/null || true
|
||
if [ ! -f "$SHIM" ] || [ "$(cat "$SHIM" 2>/dev/null)" != "$SHIM_BODY" ]; then
|
||
printf '%s' "$SHIM_BODY" > "$SHIM" 2>/dev/null && chmod 0755 "$SHIM" 2>/dev/null || true
|
||
fi
|
||
|
||
# ── 云令牌:显式环境变量 → ~/.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 时调 login 工具(浏览器点一下即可);无该工具的形态用 ~/.deta/bin/deta login"
|
||
fi
|
||
|
||
echo "[deta] 档位=${PROFILE} 运行时=${ROOT} 工作区=${WS} 工具面=${DETA_TOOL_SURFACE} 云令牌=${CLOUD_STATE}" >&2
|
||
|
||
exec node "$ENTRY" "$@"
|