Skip to content

fix(sessions): fold Cursor Tasks under Agent Sub-Sessions like Codex#262

Open
zephyr110 wants to merge 3 commits into
wxtsky:mainfrom
zephyr110:fix/cursor-ide-subagent-session-fold
Open

fix(sessions): fold Cursor Tasks under Agent Sub-Sessions like Codex#262
zephyr110 wants to merge 3 commits into
wxtsky:mainfrom
zephyr110:fix/cursor-ide-subagent-session-fold

Conversation

@zephyr110

@zephyr110 zephyr110 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Routing: Honor Agent Sub-Sessions (separate / merge / hide) for Cursor cursor / cursor-cli hooks whose transcript_path is under …/agent-transcripts/<parentId>/… while session_id is a child. Merge rewrites to the parent + agent_id; hide drops the child; separate (default) keeps a separate card — no forced merge.
  • Lifecycle: After Stop, record closed Task ids and drop idle orphan cards so a still-open IDE process cannot revive them. Keep the parent active while merged Tasks are still running. Deny/drop late Permission / Question / AskUserQuestion for closed Tasks. Relaunch on UserPromptSubmit / beforeSubmitPrompt. When splitting to separate, do not tail the parent transcript twice.
  • Hardening: Denying or answering a merged Task must not idle the parent card. An idle orphan must not overwrite a live merged Task. Only Task cards (transcript parent ≠ session id) self-close on Stop; parent chats keep cliPid. Persist closedSubagentIds. Settings copy mentions Cursor Task/subagent.
  • AppState teardown: Allow AppState deinit off the main actor (async XCTest / ARC). FSEvents callbacks hold a weak-boxed watcher so queued main-queue deliveries stay safe; avoids MainActor.assumeIsolated traps.
  • Tests: CursorSessionFoldingTests, AppStateCursorSubsessionTests, SessionPersistenceTests, AppStateDeinitTests.

中文说明

  • 路由: Cursor(cursor / cursor-cli)在「子 session_id + transcript 仍指向父对话」时,走同一套 Agent 子会话设置。合并 → 父 session + agent_id;隐藏 → 丢弃;默认独立显示,不强制合并。
  • 生命周期: Stop 后写入 closed,并丢掉空闲孤儿卡,避免 IDE 进程仍在时被拉活;父 turn 结束时若仍有合并中的 Task,父卡保持活跃;closed 后的晚到 Permission/Question/AskUserQuestion 直接拒绝或丢弃;新 prompt 可重新打开;拆成独立卡时不重复 tail 父 transcript。
  • 加固: 合并态 deny/回答不得把父卡打成 idle;空闲孤儿卡不得覆盖正在跑的合并 Task;仅 Task 卡(transcript 父 id ≠ 本卡 id)在 Stop 时自记录 closed,父会话保留 cliPid;持久化 closedSubagentIds;设置文案补充 Cursor Task/subagent。
  • AppState 销毁: 允许非主线程 deinit(异步 XCTest / ARC)。FSEvents 经弱引用 box 回调,避免 MainActor.assumeIsolated 崩溃。
  • 测试: 同上,另含 AppStateDeinitTests

Test Plan

  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/DeveloperCursorSessionFoldingTests (24), AppStateCursorSubsessionTests (26), SessionPersistenceTests (6), AppStateDeinitTests (1) — all passed
  • Settings → Behavior → Agent Sub-Sessions: copy mentions Cursor; default Show separately / 独立显示 (verified: L10n + SettingsDefaults.pluginSessionMode == "separate")
  • Manual separate: Cursor Task → separate card; Stop is not revived while IDE stays open (unit coverage: separate leave/split + Stop self-tombstone + no IDE-ppid revive)
  • Manual merge: Task appears under the parent; parent stays active if Task still runs after parent AfterAgentResponse / Stop (unit coverage: fold + parent keeps active)
  • Manual hide: Task does not appear as a card (unit coverage: hide removes/clears cards)
  • Manual: after merged Task Stop, late Permission / Question / AskUserQuestion are denied/dropped; a new prompt relaunches cleanly (unit coverage: closed-agent deny/drop + UserPromptSubmit reopen)
  • Manual: deny a merged Task Permission — parent stays .running with tool Agent, not .idle (unit coverage: testMergedPermissionMarksSubagentWaitingApproval)
  • Confirm async XCTest suites that construct AppState no longer SIGTRAP on teardown (AppStateDeinitTests passed)

Cursor IDE Tasks use a child session_id while transcript_path still points at
the parent chat, which created duplicate cards. Honor separate/merge/hide,
keep closed subagent ids across Stop (and idle-orphan merge drops), deny late
Permission/AskUserQuestion/Question for closed agent ids, drop idle orphans
without resuscitating via a shared IDE pid, fill missing parent identity from
merge-first Task hooks, reopen Cursor Tasks via beforeSubmitPrompt after Stop,
keep the parent active while folded Tasks run, and avoid dual-tailing the
parent transcript when splitting to separate cards.
Keep folded deny/answer from idling the parent, drop idle orphans without
overwriting live Tasks, and only self-tombstone foldable separate Task cards.
Async XCTest teardown released AppState off MainActor and trapped in
assumeIsolated; use weak-boxed FSEvents teardown so discovery stays safe.
nguyenvanduocit pushed a commit to nguyenvanduocit/CodeIsland that referenced this pull request Jul 15, 2026
…atch added to T-073

No new commits to wxtsky/CodeIsland since v1.0.30 (Jul 10). One new open
PR wxtsky#262 (Jul 14): fix(appstate) ProjectsWatcherBox for FSEvents teardown
safety — noted as prerequisite for T-073 implementation. vibe-island
unchanged. No new GitHub issues created.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X1rG9TcKyFd2mpEVXb9n6k
nguyenvanduocit pushed a commit to nguyenvanduocit/CodeIsland that referenced this pull request Jul 16, 2026
Upstream quiet since v1.0.30 (Jul 10). One new watch item:
- T-076: panel intermittently shifts from notch to upper-left corner
  on macOS 27.0 beta (issue wxtsky#263, M5 Pro, no upstream fix yet)

Skip: PR wxtsky#264 (OMP), PR wxtsky#262 (Cursor Tasks), issue wxtsky#265 (Cursor) —
all non-Claude CLIs or Cursor-specific.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P5RZPP2LLwKBjbXuqKxDjf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant