fix: port precheck filters to LISTEN sockets only#74
fix: port precheck filters to LISTEN sockets only#74raysonmeng wants to merge 6 commits intomasterfrom
Conversation
…llaboration sections to instruction files - 新增 marker-section.ts:幂等标记注入工具(支持创建/追加/替换三种情况) - 新增 collaboration-content.ts:定义 CLAUDE.md 和 AGENTS.md 的协作模板(何时协作、能力对照表、启动流程) - 修改 cli/init.ts:在 Step 3 调用 writeCollaborationSections 写入/更新协作段落 - 修改 bridge.ts:首次 TUI 连接时推送 kickoff 消息,触发 Claude 进入协作模式 - 新增 13 个单元测试覆盖 marker 工具和 init 集成 New: marker-section.ts — idempotent marker-based section injection utility (create/append/replace) New: collaboration-content.ts — collaboration templates for CLAUDE.md and AGENTS.md (when to collaborate, capability table, startup flow) Modified: cli/init.ts — Step 3 calls writeCollaborationSections to write/update collaboration sections Modified: bridge.ts — push kickoff message on first TUI connect transition to activate collaboration mode Added 13 unit tests covering marker utility and init integration
…off message 首次双方就绪时,向 Codex 注入完整协作指引(提议分工、通信方式), 重连时仍使用简短的状态消息,避免重复。 与 Claude 侧的 bridge.ts kickoff 对等。 On first mutual readiness, inject full collaboration kickoff to Codex (propose division of labor, communication method). Reconnects still use brief status message to avoid repetition. Symmetric with Claude-side kickoff in bridge.ts.
AgentBridge 始终作为 Claude Code 插件运行,channel 投递可用。 push 失败时已有 per-message fallback 到 pull 队列。 解决用户反馈的"收不到消息"问题。 AgentBridge always runs as a Claude Code plugin with channel support. Push failure already falls back to pull queue per-message. Fixes user-reported issue of not receiving messages in pull mode.
…laboration sections - CLAUDE.md:abg init 生成的协作段落 + code-review-graph MCP 工具说明 - plugins/:同步 bridge-server.js 和 daemon.js 构建产物 - .gitignore:排除 .code-review-graph/ 目录
- bug_005 (ultrareview): notifyCodexClaudeOnline 在 Codex turn 进行中 被 injectMessage 拒绝时会把 codexCollaborationKickoffSent latch 成 true,导致 kickoff 消息永久丢失。现在改为仅在 inject 成功后才 latch 三个 flag,并在 turnCompleted 后自动重试延迟的 kickoff。 同步修复 plugins/agentbridge/server/daemon.js bundle。 - bug_001: upsertMarkedSection 在 CLAUDE.md/AGENTS.md 含孤立 marker 或端序反转时会静默 append / 错序切片,二次运行会吞掉用户笔记。 现在增加 startIdx < endIdx 守卫;marker 畸形时抛清晰错误,init.ts per-file catch,skip 畸形文件而不阻断其他文件。 - 文档 drift: CLAUDE.md 中 macOS 状态目录改为 AgentBridge(大写), 与 state-dir.ts 对齐。 Fix kickoff silently dropped when Claude attaches mid-turn; guard marker-section against malformed marker files.
`lsof -ti :PORT` returns any process with an FD referencing the port,
including stale CLOSED outbound client connections. When a Codex TUI
process crashed (the well-known turn/steer & turn/interrupt 1005 bug)
its WS to port 4501 stayed in CLOSED state with the FD lingering. On
the next `abg claude` startup, the daemon misclassified that zombie's
outbound FD as a foreign listener and refused to start with:
Failed to start Codex: Port 4501 is already in use by non-Codex
process(es): PID(s) 47673.
Fix: scope the lsof query to `-sTCP:LISTEN` so only actual listeners
count as "in use". Stale outbound FDs are correctly ignored.
Tests: regression test exercises real lsof against a live listener +
post-close FD scenario to lock the behavior in.
—
`lsof -ti :PORT` 会返回任何引用该端口的 FD,包括崩溃后残留的
CLOSED outbound 客户端连接。Codex TUI 因为 turn/steer & turn/interrupt
的上游 1005 闪退 bug 挂掉后,僵尸进程的 4501 出站 FD 还在,
下次 `abg claude` 启动时,daemon 把这个僵尸 FD 误判成外部监听,
直接报 "Port 4501 is already in use" 拒绝启动。
修复:lsof 加 `-sTCP:LISTEN`,只把真正的监听 socket 算作占用,
残留 outbound FD 正确忽略。
测试:用真实 lsof 跑 listener + post-close FD 场景做回归。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c992797a98
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Default to push — AgentBridge always runs as a Claude Code plugin | ||
| // with --dangerously-load-development-channels, so channel delivery | ||
| // is available. If push fails, pushViaChannel already falls back to | ||
| // queueForPull per-message. | ||
| this.resolvedMode = "push"; | ||
| this.log("Delivery mode defaulting to push (set AGENTBRIDGE_MODE=pull to use polling instead)"); |
There was a problem hiding this comment.
Keep auto mode in pull until channel support is verified
Auto mode now always resolves to push, but this codebase only falls back to pull when server.notification(...) throws. MCP notifications are fire-and-forget (no delivery ack), so if Claude is started in a context that does not actually consume notifications/claude/channel (for example a direct/non-channel launch), the send can succeed while the message is never shown and never queued for get_messages, causing silent message loss. Auto mode should stay in pull (or switch to push only after explicit capability confirmation).
Useful? React with 👍 / 👎.
Summary
abg claude/abg codex启动时,daemon 因为僵尸 Codex TUI 进程残留的 outbound FD 误判端口被占用,直接报Port 4501 is already in use by non-Codex process(es)拒绝启动的问题lsof -ti :PORT替换为lsof -ti tcp:PORT -sTCP:LISTEN,只把真正在 listen 的 socket 算作占用Bug 还原
abg claude,daemon 调lsof -ti :4501,残留 FD 被算作占用ps -p PID看 cmdline 是codex --enable tui_app_server --remote ...,匹配app-server(实际是tui_app_server含下划线)失败foreignPids→ 抛错拒绝启动Fix
src/codex-adapter.ts:1186抽出 staticbuildPortListenLsofCommand(port),内部用-sTCP:LISTEN过滤,checkPorts两处 lsof 调用都走它。Test plan
LISTEN-only filter(2 个),用真实net.createServer+Socket模拟 listener+stale outbound FD 场景,验证旧 impl 会误报、新 impl 不误报bun run typecheck✅bun test src全 194 测试通过 ✅bun run build:plugin已重新打包 daemon.jsagentbridge claude能正常启动agentbridge claude不再报 "non-Codex process" 错🤖 Generated with Claude Code