ocn 定时执行方案(LaunchAgent)¶
状态: ✅ 已完成
创建日期: 2026-03-27 最后更新: 2026-03-27
背景¶
当前 ocn 脚本的核心动作是:
- 用
security find-generic-password -s "Claude Code-credentials" -w从 macOS Keychain 取出 Claude 凭证 - 生成或更新
~/.claude/.credentials.json - 同步到
~/.local/share/opencode/auth.json
手动在终端前台执行时,脚本可以正常完成;但放进 crontab 后,会卡在或失败在下面这一步:
原因判断¶
在当前 Mac 环境里,ocn 依赖 security 访问登录用户的 Keychain。
cron 的运行环境和交互式登录 shell 不同,通常缺少下面这些条件:
- 登录图形会话上下文
- 已解锁的登录钥匙串上下文
- 某些需要用户授权的 Keychain 访问路径
- 完整的用户环境变量和 PATH
因此,ocn 这种需要访问 Keychain 的脚本,不适合放到 crontab 里做长期定时任务。
推荐方案¶
使用 macOS 的 LaunchAgent,不要使用 crontab。
原因:
LaunchAgent运行在当前登录用户的会话中,更适合访问 Keychain- 可以设置固定时间间隔执行
- 可以配置开机登录后自动加载
- 可以直接把标准输出和错误输出写入日志文件
目标行为¶
建议把 ocn 配置成:
- 用户登录后自动加载
- 每 30 分钟执行一次
- 每次执行都把日志写到
/tmp/ocn.out.log和/tmp/ocn.err.log - 仍然保持脚本本身可手动执行
LaunchAgent 配置文件¶
建议创建文件:
~/Library/LaunchAgents/com.pengxin.ocn.plist
内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.pengxin.ocn</string>
<key>ProgramArguments</key>
<array>
<string>/Users/pengxin/.sh/ocn</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>1800</integer>
<key>StandardOutPath</key>
<string>/tmp/ocn.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/ocn.err.log</string>
</dict>
</plist>
安装步骤¶
1. 创建 LaunchAgents 目录¶
2. 写入 plist 文件¶
cat > ~/Library/LaunchAgents/com.pengxin.ocn.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.pengxin.ocn</string>
<key>ProgramArguments</key>
<array>
<string>/Users/pengxin/.sh/ocn</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>1800</integer>
<key>StandardOutPath</key>
<string>/tmp/ocn.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/ocn.err.log</string>
</dict>
</plist>
EOF
3. 重新加载配置¶
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.pengxin.ocn.plist 2>/dev/null || true
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.pengxin.ocn.plist
4. 立即手动触发一次¶
验证方法¶
查看 agent 是否已加载¶
查看标准输出和错误日志¶
预期标准输出¶
正常情况下,/tmp/ocn.out.log 里应该能看到类似:
[INFO] Generating auth.json from Claude credentials...
[INFO] Updating anthropic auth in place...
[INFO] Done.
[INFO] Next refresh is needed in 1h 8m 19s (2026-03-27 18:00:53 PDT)
如果 expiresAt 未变化,则应该看到:
[INFO] expiresAt matches: 1774659653714
[INFO] Next refresh is needed in 1h 8m 19s (2026-03-27 18:00:53 PDT)
[INFO] Skipping update.
常见问题¶
为什么不用 crontab¶
因为当前脚本依赖 Keychain,而 cron 对这类访问不稳定。即使补全 PATH,也不能保证 security 在 cron 环境中稳定读取到登录用户的凭证。
为什么要用绝对路径¶
LaunchAgent 的环境通常比交互式 shell 更精简。当前 ocn 脚本已经足够简单,但如果后续新增依赖,优先使用绝对路径会更稳。
是否需要开机后自动执行¶
需要。RunAtLoad 为 true 可以保证用户重新登录后,定时任务自动恢复。
后续可选优化¶
- 把
/tmp/ocn.out.log和/tmp/ocn.err.log改到固定目录,例如~/.local/share/ocn/ - 在
ocn中增加失败重试和更明确的错误日志 - 在
ocn成功更新时追加一条简短的时间戳日志,便于追踪最近一次成功同步时间