File size: 5,202 Bytes
e504204 020b280 e120fc9 e504204 e120fc9 f627b27 852f801 19971ab 852f801 ec321fa f627b27 852f801 ae829c4 e120fc9 8db91f8 e120fc9 2881109 e120fc9 8db91f8 2881109 8db91f8 852f801 fe14f50 8db200f fe14f50 c85d076 fe14f50 8db200f 8db91f8 0345de5 8db91f8 8db200f 83952c5 8db91f8 83952c5 8db91f8 5053727 83952c5 8db200f 8db91f8 fe14f50 e504204 03763a5 8db91f8 852f801 8db91f8 852f801 8db91f8 b9c4570 8db91f8 852f801 f627b27 852f801 4f7e6e2 8db91f8 852f801 8db91f8 e120fc9 ad96989 8db91f8 03763a5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #!/bin/bash
set -e
# 1. 创建持久化挂载目录
mkdir -p /data/.claude /data/.cloudcli /data/app /data/.taskmaster /data/.codex_data/sessions /data/.codex_data/state
# 2. 软链接常规目录
if [ ! -L "$HOME/.claude" ]; then
rm -rf "$HOME/.claude"
ln -s /data/.claude "$HOME/.claude"
fi
if [ ! -L "$HOME/.claude.json" ]; then
rm -f "$HOME/.claude.json"
ln -s /data/.claude.json "$HOME/.claude.json"
fi
if [ ! -L "$HOME/.cloudcli" ]; then
rm -rf "$HOME/.cloudcli"
ln -s /data/.cloudcli "$HOME/.cloudcli"
fi
if [ ! -L "$HOME/.taskmaster" ]; then
rm -rf "$HOME/.taskmaster"
ln -s /data/.taskmaster "$HOME/.taskmaster"
fi
if [ ! -L "$HOME/app" ]; then
ln -s /data/app "$HOME/app"
fi
# ==================== 针对 .codex 的安全持久化 ====================
# 清理可能存在的旧软链接
[ -L "$HOME/.codex" ] && rm -f "$HOME/.codex"
mkdir -p "$HOME/.codex"
# 1. 软链接 sessions(文本 jsonl 在网络卷完全安全)
[ -d "$HOME/.codex/sessions" ] && [ ! -L "$HOME/.codex/sessions" ] && rm -rf "$HOME/.codex/sessions"
ln -sf /data/.codex_data/sessions "$HOME/.codex/sessions"
# 2. 恢复 SQLite 元数据与索引(从网络卷复制到容器本地磁盘,避免网络锁损坏)
if [ -d "/data/.codex_data/state" ]; then
cp -u /data/.codex_data/state/*.sqlite* "$HOME/.codex/" 2>/dev/null || true
cp -u /data/.codex_data/state/*.jsonl "$HOME/.codex/" 2>/dev/null || true
fi
# 3. 后台定时同步线程:定期将本地生成的 SQLite 和 session_index 备份回 /data
(
while true; do
sleep 60
if [ -d "$HOME/.codex" ]; then
mkdir -p /data/.codex_data/state
# 同步 sqlite 与 index 文件
cp -u "$HOME"/.codex/*.sqlite* /data/.codex_data/state/ 2>/dev/null || true
cp -u "$HOME"/.codex/*.jsonl /data/.codex_data/state/ 2>/dev/null || true
fi
done
) &
# ===================================================================
# 3. 自动生成 Claude Code 配置
mkdir -p "$HOME/.claude"
cat <<EOF > "$HOME/.claude/settings.json"
{
"cleanupPeriodDays": 720,
"env": {
"API_TIMEOUT_MS": "1800000",
"BASH_DEFAULT_TIMEOUT_MS": "1800000",
"BASH_MAX_TIMEOUT_MS": "7200000",
"ANTHROPIC_BASE_URL": "${ANTHROPIC_BASE_URL:-}",
"ANTHROPIC_AUTH_TOKEN": "${ANTHROPIC_AUTH_TOKEN:-}",
"CLAUDE_CODE_ATTRIBUTION_HEADER": "0",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"DISABLE_INSTALLATION_CHECKS": "1",
"CLAUDE_CODE_PROXY_RESOLVES_HOSTS": "1",
"CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1",
"ENABLE_TOOL_SEARCH": "true",
"DISABLE_AUTOUPDATER": "1",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-sonnet-x[1m]",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-sonnet-x[1m]",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-x[1m]",
"ANTHROPIC_MODEL": "claude-sonnet-x[1m]",
"ANTHROPIC_REASONING_MODEL": "claude-sonnet-x[1m]"
},
"permissions": {
"allow": [
"Read",
"Write",
"Edit",
"Bash(*)",
"Glob",
"Grep",
"Agent",
"WebFetch",
"WebSearch",
"NotebookEdit",
"mcp__serper__google_search",
"mcp__tavily__tavily_search",
"mcp__tavily__tavily_research"
],
"deny": [
"Read(.*env*)",
"Read(~/.ssh/*)",
"Bash(rm -rf / *)"
]
},
"skipWebFetchPreflight": true,
"effortLevel": "high",
"autoUpdatesChannel": "latest"
}
EOF
# 4. 自动生成 Codex 配置
CODEX_KEY_RESOLVED="${CODEX_API_KEY:-}"
if [ -z "$CODEX_KEY_RESOLVED" ] && [ -f /data/.codex/gw_token ]; then
CODEX_KEY_RESOLVED="$(head -n 1 /data/.codex/gw_token | tr -d '[:space:]')"
fi
if [ -n "$CODEX_KEY_RESOLVED" ]; then
export OPENAI_API_KEY="$CODEX_KEY_RESOLVED"
fi
cat <<EOF > "$HOME/.codex/config.toml"
cli_auth_credentials_store = "file"
model_provider = "${CODEX_PROVIDER:-custom}"
model = "${CODEX_MODEL:-gpt-5.6-luna}"
sandbox_mode = "danger-full-access"
approval_policy = "never"
[model_providers.custom]
name = "Custom"
base_url = "${CODEX_BASE_URL:-https://cpa.freecode.eu.cc/v1}"
wire_api = "responses"
env_key = "OPENAI_API_KEY"
EOF
cat <<EOF > "$HOME/.codex/auth.json"
{
"OPENAI_API_KEY": "${CODEX_KEY_RESOLVED:-sk-dummy-key}"
}
EOF
# 5. 创建 codex wrapper 兜底(task-master-ai 内置 codex 不在 PATH 中;
# 集成端无环境变量启动时,wrapper 自动从 gw_token 注入凭证)
if [ -w /usr/local/bin ] && [ ! -e /usr/local/bin/codex ] && [ -x /usr/local/lib/node_modules/task-master-ai/node_modules/.bin/codex ]; then
cat <<'WEOF' > /usr/local/bin/codex
#!/bin/bash
if [ -z "$OPENAI_API_KEY" ] && [ -f /data/.codex/gw_token ]; then
export OPENAI_API_KEY="$(head -n 1 /data/.codex/gw_token)"
fi
exec /usr/local/lib/node_modules/task-master-ai/node_modules/.bin/codex "$@"
WEOF
chmod +x /usr/local/bin/codex 2>/dev/null || true
fi
# 6. 全局读写赋权(随后收紧 gw_token 权限,维持 600 保密要求)
chown -R 1000:1000 /data "$HOME" 2>/dev/null || true
chmod -R 777 /data "$HOME" 2>/dev/null || true
[ -f /data/.codex/gw_token ] && chmod 600 /data/.codex/gw_token 2>/dev/null || true
# 7. 切换并启动
mkdir -p /home/node/app 2>/dev/null || true
cd /home/node/app || cd /
exec "$@"
|