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 "$@"