Skip to content

feat(desktop): agent icon in v2 terminal pane via lifecycle hooks#4232

Merged
Kitenite merged 18 commits into
mainfrom
agent-lifecycle-hooks-ter
May 9, 2026
Merged

feat(desktop): agent icon in v2 terminal pane via lifecycle hooks#4232
Kitenite merged 18 commits into
mainfrom
agent-lifecycle-hooks-ter

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 8, 2026

Summary

  • Carries an AgentIdentity (agentId, optional sessionId/definitionId) end-to-end on the existing v2 agent:lifecycle hook so the running agent is identifiable per terminal — defined once in @superset/shared/agent-identity and reused by the hook receiver, the WS event bus, and the renderer.
  • Pane icon now swaps to the agent's preset logo (Claude, Codex, Gemini, OpenCode, Cursor, Copilot, Amp, Mastracode, Pi, Droid) the moment the hook fires, falling back to the generic terminal glyph. Live binding store (useV2AgentBindingStore) is keyed by terminalId, set by HostNotificationSubscriber, cleared on terminal:lifecycle exit.
  • Registers the missing SessionStart / SessionEnd hooks on every agent that natively exposes them (Claude, Mastra, Droid, Gemini, Cursor, OpenCode, Pi). Codex schema has no SessionEnd so only SessionStart was added there; Copilot already had both.
  • Upgrades Cursor, Copilot, Gemini hook scripts to dispatch the v2 payload (with v1 fallback) so non-Claude/Codex/Mastra agents also drive the icon. OpenCode plugin and Pi extension stamp SUPERSET_AGENT_ID so the same payload shape flows through.

Test plan

  • bun run typecheck clean across 29 packages
  • bun run lint clean
  • notify-hook.test.ts (6/6) — asserts v2 payload includes agent.agentId/agent.sessionId; new cases assert cursor/copilot/gemini scripts each contain the v2 dispatch + payload
  • notifications.test.ts (6/6) — new cases for identity passthrough, empty-string normalization, missing agentId drop
  • agent-wrappers.test.ts (29/29)
  • v2-agent-bindings/store.test.ts (5/5) — set/clear, retain on identical Stop, replace on different sessionId/agentId, isolation
  • Mutation-verified: deleting \$SUPERSET_HOST_AGENT_HOOK_URL from cursor-hook.template.sh correctly fails the new v2-dispatch test
  • Manual: run claude in a v2 terminal → Claude logo replaces terminal glyph; /exit then codex → switches to Codex glyph; close terminal → glyph clears

Notes

  • All new fields are optional at every layer; legacy hooks that don't stamp SUPERSET_AGENT_ID continue to work and just don't trigger the icon swap.
  • Design doc at apps/desktop/plans/20260507-1659-agent-lifecycle-hooks-terminal-binding.md.

Summary by cubic

Shows the running agent’s icon in v2 terminal panes and links v2 terminal presets to host-service agent configs for live updates. Adds Amp lifecycle via a system plugin and splits session lifecycle from per-turn signals so panes don’t show false “working” states (v2-only via SUPERSET_TERMINAL_ID + SUPERSET_HOST_AGENT_HOOK_URL).

  • New Features

    • Carries AgentIdentity end-to-end; defined in @superset/shared/agent-identity and re-exported from @superset/workspace-client. Bound per terminalId, set on agent:lifecycle, cleared on terminal:lifecycle exit.
    • TerminalPaneIcon swaps the pane icon to the agent logo (Claude, Codex, Gemini, Cursor, Copilot, OpenCode, Amp, Mastracode, Pi, Droid); used in TerminalSessionDropdown with pane-registry getIcon as a fallback.
    • Maps session lifecycle to Attached/Detached (icon binding only). Start/Stop keep driving status and the chime.
    • Amp lifecycle wired via a system plugin that forwards session.start/agent.start/agent.end to our notify hook; the wrapper exports SUPERSET_AGENT_ID so identity flows into the payload.
    • V2 presets link to host-service agent config ids (not presetId) for accurate commands and icons; older rows fall back to presetId and auto-migrate when unambiguous. Launcher refetches configs at run time; Agents settings patches cache on save; QuickAdd accepts a separate iconId.
  • Bug Fixes

    • Drops all v1 lifecycle-hook fallbacks; v2-only guards now use SUPERSET_TERMINAL_ID.
    • Codex: restores per-turn Start/permission via reliable rollout tail; quotes notify path; renames --enable codex_hooks to --enable hooks; inlines SUPERSET_AGENT_ID=codex.
    • Cursor/Gemini/Copilot/OpenCode/Pi: bump hook markers to v2, read stdin consistently, auto-approve permission hooks with JSON to avoid blocking, and stamp/inherit SUPERSET_AGENT_ID. Gemini also recognizes flat command when cleaning old managed entries.
    • Renderer ignores Attached for status and clears transient status on Detached, while still updating the icon binding.

Written for commit 94c0f4a. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Terminal pane headers now show agent icons for running CLI agents.
    • Host lifecycle notifications can include agent identity (agentId + optional session) enabling UI binding.
  • Behavior Changes

    • Lifecycle events include new Attached/Detached signals that update pane binding without playing sounds or native notifications.
    • Agent lifecycle dispatch moved to v2 host-only notifications for better reliability.
  • Tests

    • Added tests for agent identity propagation, terminal-scoped bindings, and event-type mapping.

…cycle hooks

Wires the existing v2 agent-lifecycle hook through to a per-terminal binding
store so the pane's primary icon swaps to the running agent's logo (Claude,
Codex, Gemini, …) the moment the hook fires, falling back to the generic
terminal glyph otherwise. Adds the missing SessionStart/SessionEnd
registrations across every agent that exposes them and gives Cursor, Copilot,
Gemini, OpenCode, and Pi a v2 dispatch path so they all carry agent identity.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extends lifecycle hooks to carry an AgentIdentity from wrappers through hook scripts and the host-service, records last-seen agent identity per terminal in a renderer store, and renders the agent's icon in the terminal pane header.

Changes

Agent Lifecycle Hooks and Terminal Binding

Layer / File(s) Summary
Shared Types
packages/shared/src/agent-identity.ts, packages/shared/package.json
New AgentIdentity interface with required agentId and optional sessionId and definitionId; exported as ./agent-identity subpath.
Event Types / Exports
packages/host-service/src/events/types.ts, packages/workspace-client/src/lib/eventBus.ts, packages/workspace-client/src/index.ts
AgentLifecycleMessage and AgentLifecyclePayload extended with optional agent?: AgentIdentity; workspace-client re-exports AgentIdentity type.
Wrapper Infrastructure
apps/desktop/src/main/lib/agent-setup/agent-wrappers-common.ts
buildWrapperScript() accepts options: BuildWrapperScriptOptions with optional agentId and injects export SUPERSET_AGENT_ID="..." into the generated wrapper when provided.
Agent Wrapper Implementations
apps/desktop/src/main/lib/agent-setup/agent-wrappers-*.ts
Agent wrappers (amp, claude, codex, opencode, copilot, cursor, droid, gemini, mastra, etc.) updated to pass agentId to buildWrapperScript() and many managed hook lists expanded to include SessionStart/SessionEnd.
Hook Templates
apps/desktop/src/main/lib/agent-setup/templates/*-hook.template.sh, *-plugin.template.js, *-extension.template.ts
Hook templates parse SUPERSET_AGENT_ID and optional session_id from stdin, print {} to stdout immediately, and when configured post a v2 JSON payload including terminalId, eventType, and a nested agent object (agentId/sessionId) to SUPERSET_HOST_AGENT_HOOK_URL.
Host-Service Router
packages/host-service/src/trpc/router/notifications/notifications.ts, notifications.test.ts
hook endpoint accepts optional agent input, Zod-validates and normalizes it (empty strings → undefined), and includes normalized agent in broadcasted lifecycle events when present.
Event Mapping
packages/host-service/src/events/map-event-type.ts, map-event-type.test.ts
Add Attached/Detached lifecycle types and map SessionStart/SessionEnd variants to them; existing Start/Stop/PermissionRequest mappings preserved; tests added.
Renderer Store
apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts, store.test.ts, index.ts
Zustand store tracks terminal→AgentIdentity bindings with setBinding() deduplication (identity equality + lastEventAt ordering) and clearBinding() removal; selector factory provided.
Notification Subscriber
apps/desktop/src/renderer/.../HostNotificationSubscriber/HostNotificationSubscriber.tsx
Updates to set binding when lifecycle payload includes agent and clear binding on terminal exit.
Terminal Icon Component
apps/desktop/src/renderer/.../TerminalPane/components/TerminalPaneIcon/TerminalPaneIcon.tsx, index.ts
New TerminalPaneIcon component selects per-terminal binding from store, derives agentId, looks up preset icon, and renders branded image with alt/title or falls back to a terminal glyph.
Pane Registry Integration
apps/desktop/src/renderer/.../usePaneRegistry/usePaneRegistry.tsx, TerminalSessionDropdown
Pane registry and session dropdown now use TerminalPaneIcon for terminal icons instead of a static glyph.
Notification Behavior & Status
apps/desktop/src/renderer/.../V2NotificationController/lib/*
Attached/Detached events no longer play ringtones or show native notifications; status transition logic updated and tests added.
Tests & Documentation
apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts, packages/host-service/src/trpc/router/notifications/notifications.test.ts, packages/host-service/src/events/map-event-type.test.ts, apps/desktop/plans/20260507-1659-agent-lifecycle-hooks-terminal-binding.md
Tests added/updated to assert v2 notify payload structure, per-agent template dispatch, host-service forwarding and normalization, event mapping, and store semantics; design spec documents protocol and test plan.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

"🐰 I hop and stamp each wrapper's shell,

Hooks whisper names where agents dwell,
The store remembers who passed by,
An icon peeks at every tty,
Hooray — a carrot for that clever tie!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main feature: displaying the agent icon in v2 terminal panes through lifecycle hook integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering changes, design rationale, test plan, and design documentation reference.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent-lifecycle-hooks-ter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…d getIcon slot

Terminal panes set `renderTitle`, which makes DefaultHeaderContent skip the
`getIcon` slot entirely (panes/.../DefaultHeaderContent.tsx:24-26). The
visible icon is the TerminalSquare inside TerminalSessionDropdown, so route
the agent-icon swap there. The pane-registry getIcon stays wired for
defensive consistency in case rendering ever falls back.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 32 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/main/lib/agent-setup/templates/gemini-hook.template.sh">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/gemini-hook.template.sh:20">
P2: `SessionEnd` is passed through as-is, but the v1 fallback mapper does not recognize `SessionEnd`, so stop events can be dropped on legacy/fallback dispatch.</violation>
</file>

<file name="apps/desktop/src/main/lib/agent-setup/templates/opencode-plugin.template.js">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/opencode-plugin.template.js:168">
P1: `session.deleted` can misclassify deleted child sessions as root sessions and emit a false `SessionEnd` event.</violation>
</file>

<file name="apps/desktop/src/main/lib/agent-setup/templates/copilot-hook.template.sh">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/copilot-hook.template.sh:19">
P1: v1 fallback now sends `SessionStart`/`SessionEnd` event types, which can break legacy `/hook/complete` handling that expects `Start`/`Stop`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/desktop/src/main/lib/agent-setup/templates/opencode-plugin.template.js Outdated
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 8, 2026

Greptile Summary

This PR wires AgentIdentity end-to-end through the existing agent:lifecycle hook pipeline so the v2 terminal pane header can display a live agent logo (Claude, Codex, Gemini, etc.) while an agent is running, falling back to the generic terminal glyph when none is detected.

  • New shared type AgentIdentity defined in @superset/shared/agent-identity, re-exported through @superset/workspace-client, and threaded through tRPC → event-bus → renderer Zustand store (useV2AgentBindingStore, keyed by terminalId).
  • Hook scripts for Cursor, Copilot, and Gemini are upgraded to dispatch the v2 payload (with v1 fallback); Claude/Mastra/Droid/OpenCode/Pi wrappers export SUPERSET_AGENT_ID so notify-hook.template.sh picks it up automatically.
  • SessionStart/SessionEnd hooks are registered across all agents; the new TerminalPaneIcon component reads the store and swaps in the preset logo as soon as the first lifecycle event fires.

Confidence Score: 3/5

The icon feature is backward-compatible and safe to ship in isolation, but there is a concrete regression for Copilot's working indicator caused by a missing case in mapEventType.

The mapEventType function was not updated alongside the hook scripts: SessionEnd (PascalCase) is absent from the Stop branch while the symmetric SessionStart was correctly added to Start. Every PascalCase SessionEnd from Claude, Mastra, Droid, Gemini, Cursor, and Copilot is silently dropped. For Copilot this is a concrete regression — sessionEnd was previously the only Stop signal for the working indicator and is now lost because the hook now emits the PascalCase form which mapEventType does not handle.

packages/host-service/src/events/map-event-type.ts needs SessionEnd added to the Stop branch; apps/desktop/src/main/lib/agent-setup/templates/copilot-hook.template.sh is the most directly affected file for the existing regression.

Important Files Changed

Filename Overview
packages/host-service/src/events/map-event-type.ts Not modified in this PR but critical: SessionEnd (PascalCase) is absent from the Stop branch, silently dropping every SessionEnd event from every agent.
apps/desktop/src/main/lib/agent-setup/templates/copilot-hook.template.sh Upgrades to v2 payload and switches sessionEnd → SessionEnd; the rename causes a working-indicator regression due to the unmodified mapEventType.
apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts Well-structured Zustand store with correct isolation and out-of-order protection; minor churn on identical-identity events with newer timestamps.
packages/shared/src/agent-identity.ts New shared type file; clean AgentIdentity definition with proper optional fields and good JSDoc.
packages/host-service/src/trpc/router/notifications/notifications.ts Clean schema extension with proper empty-string normalization; normalizeAgentIdentity handles missing agentId and optional fields correctly.
apps/desktop/src/main/lib/agent-setup/templates/pi-extension.template.ts Adds session_start → SessionStart; missing session_end counterpart despite PR description claiming both are registered.
packages/workspace-client/src/lib/eventBus.ts Correctly passes the optional agent field through the event bus and re-exports AgentIdentity type.

Sequence Diagram

sequenceDiagram
    participant Agent as Agent Process
    participant Hook as Hook Script
    participant HS as host-service notifications.ts
    participant EB as EventBus
    participant Store as V2AgentBindingStore
    participant Icon as TerminalPaneIcon

    Agent->>Hook: fires SessionStart/SessionEnd/Stop
    Hook->>Hook: build v2 payload with agent identity
    Hook->>HS: POST /trpc/notifications.hook
    HS->>HS: normalizeAgentIdentity()
    HS->>HS: mapEventType(eventType)
    alt SessionStart or Start or Stop
        HS->>EB: broadcastAgentLifecycle with agent
        EB->>Store: setBinding(terminalId, identity)
        Store->>Icon: re-render with preset logo
    else SessionEnd PascalCase — BUG
        HS-->>Hook: ignored:true (200 OK)
        Note over Hook,HS: v1 fallback also skipped
    end
    Note over Store,Icon: clearBinding on terminal:lifecycle exit
Loading

Comments Outside Diff (1)

  1. packages/host-service/src/events/map-event-type.ts, line 39-49 (link)

    P1 SessionEnd (PascalCase) missing from Stop mapping — causes silent drop and working-indicator regression

    mapEventType already handles SessionStart (PascalCase → Start), but the Stop branch only lists sessionEnd (camelCase) and session_end (snake_case). Every PascalCase SessionEnd sent by Claude, Mastra, Droid, Gemini, Cursor, and Copilot returns null, triggering the early-return { success: true, ignored: true } path — the event is silently dropped and never broadcast. The most concrete regression is Copilot: before this PR sessionEnd was mapped to "Stop" in the hook script and correctly reset the working indicator; after the PR it maps to "SessionEnd" which is now dropped, leaving the working indicator permanently stuck in the "working" state after a Copilot session ends.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/host-service/src/events/map-event-type.ts
    Line: 39-49
    
    Comment:
    **`SessionEnd` (PascalCase) missing from `Stop` mapping — causes silent drop and working-indicator regression**
    
    `mapEventType` already handles `SessionStart` (PascalCase → `Start`), but the `Stop` branch only lists `sessionEnd` (camelCase) and `session_end` (snake_case). Every PascalCase `SessionEnd` sent by Claude, Mastra, Droid, Gemini, Cursor, and Copilot returns `null`, triggering the early-return `{ success: true, ignored: true }` path — the event is silently dropped and never broadcast. The most concrete regression is Copilot: before this PR `sessionEnd` was mapped to `"Stop"` in the hook script and correctly reset the working indicator; after the PR it maps to `"SessionEnd"` which is now dropped, leaving the working indicator permanently stuck in the "working" state after a Copilot session ends.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/host-service/src/events/map-event-type.ts:39-49
**`SessionEnd` (PascalCase) missing from `Stop` mapping — causes silent drop and working-indicator regression**

`mapEventType` already handles `SessionStart` (PascalCase → `Start`), but the `Stop` branch only lists `sessionEnd` (camelCase) and `session_end` (snake_case). Every PascalCase `SessionEnd` sent by Claude, Mastra, Droid, Gemini, Cursor, and Copilot returns `null`, triggering the early-return `{ success: true, ignored: true }` path — the event is silently dropped and never broadcast. The most concrete regression is Copilot: before this PR `sessionEnd` was mapped to `"Stop"` in the hook script and correctly reset the working indicator; after the PR it maps to `"SessionEnd"` which is now dropped, leaving the working indicator permanently stuck in the "working" state after a Copilot session ends.

### Issue 2 of 3
apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts:37-45
**Store update on every identical-identity event causes unnecessary re-renders**

The guard skips updates only when all identity fields match AND `existing.lastEventAt >= occurredAt`. For the common case — same `agentId`/`sessionId` but a newer `occurredAt` — the guard fails, writing a new `byTerminalId` object reference and re-rendering all `useV2AgentBindingStore` subscribers even though the displayed icon is unchanged. Consider skipping the update entirely when identity fields are identical regardless of timestamp, or updating only `lastEventAt` without replacing the `identity` reference.

### Issue 3 of 3
apps/desktop/src/main/lib/agent-setup/templates/pi-extension.template.ts:79-82
**`session_end` hook not registered for Pi despite PR description claiming both SessionStart and SessionEnd**

Only `session_start``SessionStart` was added. Pi's `session_shutdown` still fires `Stop` so the working indicator recovers, but a dedicated `session_end` hook would provide the canonical session-lifetime signal the PR aims to standardize. If Pi's API doesn't expose `session_end`, the PR description should note the omission.

Reviews (1): Last reviewed commit: "fix(desktop): swap agent icon in Termina..." | Re-trigger Greptile

Comment on lines +37 to +45
if (
existing &&
existing.identity.agentId === identity.agentId &&
existing.identity.sessionId === identity.sessionId &&
existing.identity.definitionId === identity.definitionId &&
existing.lastEventAt >= occurredAt
) {
return state;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Store update on every identical-identity event causes unnecessary re-renders

The guard skips updates only when all identity fields match AND existing.lastEventAt >= occurredAt. For the common case — same agentId/sessionId but a newer occurredAt — the guard fails, writing a new byTerminalId object reference and re-rendering all useV2AgentBindingStore subscribers even though the displayed icon is unchanged. Consider skipping the update entirely when identity fields are identical regardless of timestamp, or updating only lastEventAt without replacing the identity reference.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts
Line: 37-45

Comment:
**Store update on every identical-identity event causes unnecessary re-renders**

The guard skips updates only when all identity fields match AND `existing.lastEventAt >= occurredAt`. For the common case — same `agentId`/`sessionId` but a newer `occurredAt` — the guard fails, writing a new `byTerminalId` object reference and re-rendering all `useV2AgentBindingStore` subscribers even though the displayed icon is unchanged. Consider skipping the update entirely when identity fields are identical regardless of timestamp, or updating only `lastEventAt` without replacing the `identity` reference.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +79 to +82
pi.on("session_start", (_event, ctx) => {
if (skip(ctx)) return;
fire("SessionStart");
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 session_end hook not registered for Pi despite PR description claiming both SessionStart and SessionEnd

Only session_startSessionStart was added. Pi's session_shutdown still fires Stop so the working indicator recovers, but a dedicated session_end hook would provide the canonical session-lifetime signal the PR aims to standardize. If Pi's API doesn't expose session_end, the PR description should note the omission.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/templates/pi-extension.template.ts
Line: 79-82

Comment:
**`session_end` hook not registered for Pi despite PR description claiming both SessionStart and SessionEnd**

Only `session_start``SessionStart` was added. Pi's `session_shutdown` still fires `Stop` so the working indicator recovers, but a dedicated `session_end` hook would provide the canonical session-lifetime signal the PR aims to standardize. If Pi's API doesn't expose `session_end`, the PR description should note the omission.

How can I resolve this? If you propose a fix, please make it concise.

SessionStart fires when an agent attaches to a terminal — the agent is idle,
waiting for the first prompt. Mapping it to `Start` was making the pane show
the working spinner before the user typed anything. Split session-lifetime
events out of the per-turn cadence: `Attached`/`Detached` drive the pane
icon binding only and never touch the working indicator or play any sound.
Per-turn `Start`/`Stop` keeps its prior behavior.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/desktop/src/main/lib/agent-setup/templates/cursor-hook.template.sh (1)

57-66: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

SessionStart/SessionEnd fall through to the v1 curl when the v2 POST fails — consider adding a guard.

notify-hook.template.sh protects its v1 path with:

[ -z "$SUPERSET_TAB_ID" ] && [ -z "$SESSION_ID" ] && exit 0

cursor-hook.template.sh has no equivalent guard before the v1 curl. Since SessionStart / SessionEnd are v2-only events (the v1 /hook/complete server doesn't understand them), when the v2 POST times out or returns non-2xx the script unconditionally fires a v1 request with eventType=SessionStart or eventType=SessionEnd and a potentially empty SUPERSET_TAB_ID — producing spurious and semantically incorrect v1 traffic.

Adding a one-line guard before the v1 block mirrors the pattern in notify-hook.template.sh and suppresses these calls:

🛡️ Proposed fix
+# v1 fallback for terminals running against the legacy electron localhost server.
+# Skip if there is no legacy tab context (pure v2 terminal).
+[ -z "$SUPERSET_TAB_ID" ] && exit 0
 curl -sG "http://127.0.0.1:${SUPERSET_PORT:-{{DEFAULT_PORT}}}/hook/complete" \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/lib/agent-setup/templates/cursor-hook.template.sh`
around lines 57 - 66, Before the v1 curl block in cursor-hook.template.sh add
the same guard used in notify-hook.template.sh so v1 requests are suppressed for
v2-only events: check [ -z "$SUPERSET_TAB_ID" ] && [ -z "$SESSION_ID" ] and
skip/exit when both are empty so SessionStart/SessionEnd (v2-only) don't fall
through to the v1 /hook/complete curl; place this check immediately before the
curl that uses SUPERSET_TAB_ID, SUPERSET_TAB_ID/SESSION_ID and EVENT_TYPE to
mirror the notify-hook.template.sh pattern.
apps/desktop/src/main/lib/agent-setup/agent-wrappers-claude-codex-opencode.ts (1)

411-433: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Codex hooks.json should inline SUPERSET_AGENT_ID=codex like Claude does.

getClaudeManagedHookCommand (line 84-86) deliberately prepends SUPERSET_AGENT_ID=claude so the v2 identity flows through even when the user launches the agent outside the Superset wrapper (system PATH → real binary, no wrapper env vars). The Codex hooks.json registration here uses bare notifyScriptPath for SessionStart/UserPromptSubmit/Stop, so a user invoking codex directly will still trigger the global hooks but the v2 payload's agent.agentId will be empty, the host service will drop the agent field during normalization, and the pane icon will never bind. This silently regresses the documented goal ("show the agent's icon… complementing… outside the wrapper") for Codex.

🛠️ Suggested fix
+	// Mirror getClaudeManagedHookCommand: inline SUPERSET_AGENT_ID so the v2
+	// payload carries identity even when codex is launched outside the wrapper.
+	const codexCommand = `SUPERSET_AGENT_ID=codex ${notifyScriptPath}`;
+
 	const managedEvents: Array<{
 		eventName: "SessionStart" | "UserPromptSubmit" | "Stop";
 		definition: ClaudeHookDefinition;
 	}> = [
 		{
 			eventName: "SessionStart",
 			definition: {
-				hooks: [{ type: "command", command: notifyScriptPath }],
+				hooks: [{ type: "command", command: codexCommand }],
 			},
 		},
 		{
 			eventName: "UserPromptSubmit",
 			definition: {
-				hooks: [{ type: "command", command: notifyScriptPath }],
+				hooks: [{ type: "command", command: codexCommand }],
 			},
 		},
 		{
 			eventName: "Stop",
 			definition: {
-				hooks: [{ type: "command", command: notifyScriptPath }],
+				hooks: [{ type: "command", command: codexCommand }],
 			},
 		},
 	];

You'll likely want to also update isManagedCodexHookCommand / isSupersetManagedHookCommand matching to recognize the new prefix during reconciliation, otherwise existing entries written by previous installs will be deduped against the new form.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/main/lib/agent-setup/agent-wrappers-claude-codex-opencode.ts`
around lines 411 - 433, The Codex managedEvents entries use bare
notifyScriptPath so the v2 agent id is not injected; update the three
definitions inside managedEvents (SessionStart, UserPromptSubmit, Stop) to use
the same env-prefix form as getClaudeManagedHookCommand (i.e. prepend
SUPERSET_AGENT_ID=codex to the command string) so agent.agentId is preserved
when users run the real codex binary; also update isManagedCodexHookCommand and
isSupersetManagedHookCommand matching logic to recognize and dedupe both the old
bare notifyScriptPath and the new SUPERSET_AGENT_ID=codex-prefixed form during
reconciliation.
🧹 Nitpick comments (1)
apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts (1)

61-82: 💤 Low value

LGTM – parameterized template coverage is a good addition.

One optional note: expectedV2Payload (Line 62–63) is character-for-character identical to the literal inside the getNotifyScriptContent describe block at Line 17. Hoisting it to a module-level constant would mean a single update point if the payload shape ever changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts` around lines 61 -
82, Hoist the duplicate expectedV2Payload string into a module-level constant
and reuse it in both the "per-agent hook scripts dispatch to v2" test and the
getNotifyScriptContent describe block to avoid divergence; replace the local
expectedV2Payload declaration in the inner describe with a reference to the new
shared constant and update any imports/usages accordingly so both the template
parameterized tests (loop over "cursor-hook.template.sh",
"copilot-hook.template.sh", "gemini-hook.template.sh") and the
getNotifyScriptContent tests compare against the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.ts`:
- Line 71: The notifyCommand currently built as `const notifyCommand = \`bash
${quoteShellPath(notifyScriptPath)}\`` lacks the inline SUPERSET_AGENT_ID env
var; update notifyCommand to prefix the invocation with
`SUPERSET_AGENT_ID=mastracode` (e.g. `SUPERSET_AGENT_ID=mastracode bash <path>`)
so the v2 hook payload includes agent.agentId; locate where notifyCommand is
defined (uses quoteShellPath and notifyScriptPath and is passed into
buildWrapperScript which receives agentId: "mastracode") and change the string
construction to include the env var inline.

In `@apps/desktop/src/main/lib/agent-setup/templates/opencode-plugin.template.js`:
- Around line 150-172: The session.deleted handler can misidentify child
sessions because isChildSession(sessionID) may fail after the session is
removed; change the logic in the event.type === "session.deleted" branch to
first check event.properties?.info?.parentID (use
Boolean(event.properties?.info?.parentID)) and only fall back to await
isChildSession(sessionID) when parentID is not present; then call await
notify("SessionEnd") only if the combined child-check is false (also handle null
sessionID safely). Update the symbols in that block: event.type,
event.properties?.info?.parentID, sessionID, isChildSession, and notify.

In
`@apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/components/HostNotificationSubscriber/HostNotificationSubscriber.tsx`:
- Around line 43-47: The lifecycle handler in HostNotificationSubscriber
currently only sets a binding when payload.agent exists, leaving stale bindings
when payload.agent is absent; update the else path to clear the terminal's
binding by calling
useV2AgentBindingStore.getState().setBinding(payload.terminalId, null /* or
undefined */ , payload.occurredAt) or the store's clearBinding method if one
exists, so the UI falls back to the generic icon immediately; modify the branch
around payload.agent to set or clear via setBinding(payload.terminalId, ...)
accordingly.

In `@apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts`:
- Around line 34-52: In setBinding, guard against stale out-of-order events by
first checking if an existing binding exists and if existing.lastEventAt >=
occurredAt and returning state immediately (using state.byTerminalId and
lastEventAt), then keep the identity-equality short-circuit (compare
existing.identity.agentId/sessionId/definitionId) to avoid unnecessary writes;
otherwise update state.byTerminalId with the new { identity, lastEventAt:
occurredAt } — this ensures late events for a different identity cannot clobber
a newer binding.

---

Outside diff comments:
In
`@apps/desktop/src/main/lib/agent-setup/agent-wrappers-claude-codex-opencode.ts`:
- Around line 411-433: The Codex managedEvents entries use bare notifyScriptPath
so the v2 agent id is not injected; update the three definitions inside
managedEvents (SessionStart, UserPromptSubmit, Stop) to use the same env-prefix
form as getClaudeManagedHookCommand (i.e. prepend SUPERSET_AGENT_ID=codex to the
command string) so agent.agentId is preserved when users run the real codex
binary; also update isManagedCodexHookCommand and isSupersetManagedHookCommand
matching logic to recognize and dedupe both the old bare notifyScriptPath and
the new SUPERSET_AGENT_ID=codex-prefixed form during reconciliation.

In `@apps/desktop/src/main/lib/agent-setup/templates/cursor-hook.template.sh`:
- Around line 57-66: Before the v1 curl block in cursor-hook.template.sh add the
same guard used in notify-hook.template.sh so v1 requests are suppressed for
v2-only events: check [ -z "$SUPERSET_TAB_ID" ] && [ -z "$SESSION_ID" ] and
skip/exit when both are empty so SessionStart/SessionEnd (v2-only) don't fall
through to the v1 /hook/complete curl; place this check immediately before the
curl that uses SUPERSET_TAB_ID, SUPERSET_TAB_ID/SESSION_ID and EVENT_TYPE to
mirror the notify-hook.template.sh pattern.

---

Nitpick comments:
In `@apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts`:
- Around line 61-82: Hoist the duplicate expectedV2Payload string into a
module-level constant and reuse it in both the "per-agent hook scripts dispatch
to v2" test and the getNotifyScriptContent describe block to avoid divergence;
replace the local expectedV2Payload declaration in the inner describe with a
reference to the new shared constant and update any imports/usages accordingly
so both the template parameterized tests (loop over "cursor-hook.template.sh",
"copilot-hook.template.sh", "gemini-hook.template.sh") and the
getNotifyScriptContent tests compare against the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cf23c9ec-ed39-4d25-9fba-4831cfd2343a

📥 Commits

Reviewing files that changed from the base of the PR and between 1375f14 and eec30b8.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • apps/desktop/plans/20260507-1659-agent-lifecycle-hooks-terminal-binding.md
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-amp.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-claude-codex-opencode.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-common.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-copilot.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-cursor.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-droid.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-gemini.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.ts
  • apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts
  • apps/desktop/src/main/lib/agent-setup/templates/copilot-hook.template.sh
  • apps/desktop/src/main/lib/agent-setup/templates/cursor-hook.template.sh
  • apps/desktop/src/main/lib/agent-setup/templates/gemini-hook.template.sh
  • apps/desktop/src/main/lib/agent-setup/templates/notify-hook.template.sh
  • apps/desktop/src/main/lib/agent-setup/templates/opencode-plugin.template.js
  • apps/desktop/src/main/lib/agent-setup/templates/pi-extension.template.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/components/TerminalPaneIcon/TerminalPaneIcon.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/components/TerminalPaneIcon/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx
  • apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/components/HostNotificationSubscriber/HostNotificationSubscriber.tsx
  • apps/desktop/src/renderer/stores/v2-agent-bindings/index.ts
  • apps/desktop/src/renderer/stores/v2-agent-bindings/store.test.ts
  • apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts
  • packages/host-service/src/events/types.ts
  • packages/host-service/src/trpc/router/notifications/notifications.test.ts
  • packages/host-service/src/trpc/router/notifications/notifications.ts
  • packages/shared/package.json
  • packages/shared/src/agent-identity.ts
  • packages/workspace-client/package.json
  • packages/workspace-client/src/index.ts
  • packages/workspace-client/src/lib/eventBus.ts

Comment thread apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.ts Outdated
Comment thread apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/lib/statusTransitions.ts`:
- Around line 37-39: Split the current combined check for payload.eventType so
"Attached" remains the noop (return { clearSources: [], setStatus: null }) but
"Detached" explicitly clears transient pane state: in the branch where
payload.eventType === "Detached" return an object that lists the transient
sources to clear (e.g., include "working" and "permission" in clearSources) and
set setStatus to null while not clearing the "review" source; update the code
around payload.eventType, "Attached", "Detached" and the returned {
clearSources: [], setStatus } to implement this behavior.

In `@packages/host-service/src/events/map-event-type.ts`:
- Around line 28-40: The lifecycle mapping currently only checks PascalCase
"Attached"/"Detached" (and mixed-case session variants) and thus misses
lowercase emits; update the conditional checks that examine eventType (the
comparisons around eventType === "Attached" ... and eventType === "Detached"
...) to also accept the lowercase aliases "attached" and "detached" (and ensure
any sessionStart/sessionEnd checks already handling lowercase forms remain
consistent), so the function that maps eventType returns "Attached"/"Detached"
for those lowercase inputs as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: def83361-2630-4024-b833-1aaac8aa9c14

📥 Commits

Reviewing files that changed from the base of the PR and between eec30b8 and 54055ce.

📒 Files selected for processing (6)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/components/TerminalSessionDropdown/TerminalSessionDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/lib/lifecycleEvents.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/lib/statusTransitions.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/V2NotificationController/lib/statusTransitions.ts
  • packages/host-service/src/events/map-event-type.test.ts
  • packages/host-service/src/events/map-event-type.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/host-service/src/events/map-event-type.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/components/TerminalSessionDropdown/TerminalSessionDropdown.tsx

Comment thread packages/host-service/src/events/map-event-type.ts
…nal gates

In v2 host-service terminals only SUPERSET_TERMINAL_ID is set in the PTY env
(packages/host-service/src/terminal/env.ts:183) — SUPERSET_TAB_ID is v1-only.
Several wrapper guards only checked SUPERSET_TAB_ID, so:

- The codex wrapper's TUI session-log watcher (the per-turn Start/PermissionRequest
  source for codex) never started in v2, leaving codex panes stuck on idle while
  generating. Codex's native ~/.codex/hooks.json fires unreliably in interactive
  TUI mode, which was the original reason for the watcher.
- The OpenCode plugin returned early before installing handlers in v2.
- The Copilot wrapper skipped its hooks.json injection in v2.

All three now gate on either v1 (SUPERSET_TAB_ID) or v2 (SUPERSET_TERMINAL_ID).

Also rename `--enable codex_hooks` → `--enable hooks` in the codex wrapper:
the older flag name still works via deprecation alias but prints a noisy
warning every launch (codex 0.129+).
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh:22">
P1: The rollout watcher is not process-scoped: it can attach to another Codex session’s `rollout-*.jsonl` file and emit lifecycle events for the wrong terminal.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Comment thread apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh Outdated
Codex's official hook surface (~/.codex/hooks.json with SessionStart,
UserPromptSubmit, Stop) is the right integration point. The session-log
watcher was a workaround for older codex builds whose log shape no longer
exists in 0.129+; keeping it as an alternative path adds complexity for
no real benefit. The wrapper is now a one-liner: forward to the real
binary with --enable hooks and the legacy notify=... callback for Stop
parity.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 26 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts">

<violation number="1" location="apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts:37">
P1: The equality short-circuit drops newer same-identity events, so `lastEventAt` can go stale and allow delayed older events to overwrite the binding.</violation>
</file>

<file name="apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh:70">
P2: Watcher shutdown only targets the subshell PID; terminate child pipeline processes too to avoid orphaned `tail` processes.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

existing &&
existing.identity.agentId === identity.agentId &&
existing.identity.sessionId === identity.sessionId &&
existing.identity.definitionId === identity.definitionId
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The equality short-circuit drops newer same-identity events, so lastEventAt can go stale and allow delayed older events to overwrite the binding.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/stores/v2-agent-bindings/store.ts, line 37:

<comment>The equality short-circuit drops newer same-identity events, so `lastEventAt` can go stale and allow delayed older events to overwrite the binding.</comment>

<file context>
@@ -27,12 +27,14 @@ export const useV2AgentBindingStore = create<V2AgentBindingState>((set) => ({
 				existing.identity.sessionId === identity.sessionId &&
-				existing.identity.definitionId === identity.definitionId &&
-				existing.lastEventAt >= occurredAt
+				existing.identity.definitionId === identity.definitionId
 			) {
 				return state;
</file context>
Suggested change
existing.identity.definitionId === identity.definitionId
existing.identity.definitionId === identity.definitionId &&
existing.lastEventAt >= occurredAt

Tip: Review your code locally with the cubic CLI to iterate faster.

kill "$SUPERSET_CODEX_START_WATCHER_PID" >/dev/null 2>&1 || true
wait "$SUPERSET_CODEX_START_WATCHER_PID" 2>/dev/null || true
if [ -n "$SUPERSET_CODEX_SESSION_WATCHER_PID" ]; then
kill "$SUPERSET_CODEX_SESSION_WATCHER_PID" >/dev/null 2>&1 || true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Watcher shutdown only targets the subshell PID; terminate child pipeline processes too to avoid orphaned tail processes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/main/lib/agent-setup/templates/codex-wrapper-exec.template.sh, line 70:

<comment>Watcher shutdown only targets the subshell PID; terminate child pipeline processes too to avoid orphaned `tail` processes.</comment>

<file context>
@@ -1,5 +1,75 @@
+_superset_debug "codex exited status=$SUPERSET_CODEX_STATUS"
+
+if [ -n "$SUPERSET_CODEX_SESSION_WATCHER_PID" ]; then
+  kill "$SUPERSET_CODEX_SESSION_WATCHER_PID" >/dev/null 2>&1 || true
+  wait "$SUPERSET_CODEX_SESSION_WATCHER_PID" 2>/dev/null || true
+  _superset_debug "session watcher stopped pid=$SUPERSET_CODEX_SESSION_WATCHER_PID"
</file context>

Linked v2 presets now store the host-service agent config id in
`agentId` so multiple agents sharing a presetId (e.g., two Claude
configs) each get their own pill and resolver path. Older rows that
store presetId still resolve via fallback, and V2PresetsSection
auto-migrates them when the config id is uniquely determined.

Also: useV2PresetExecution refetches the live agent list at launch
time so command edits take effect without a remount; AgentDetail's
onChanged now hands the updated row back so the cache can be patched
optimistically; QuickAddPresets accepts a separate iconId.
@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai Bot commented May 9, 2026

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

Kitenite added 5 commits May 9, 2026 14:47
… form

Bump CURSOR_HOOK_VERSION and GEMINI_HOOK_VERSION to v2 so existing
installs re-detect the managed marker and replace stale wrapper paths
(e.g., from prior worktree-style data dirs).

Gemini's `isManaged` predicate now also matches definitions whose
top-level `command` points at the managed script, in addition to the
nested `hooks[].command` form, so both shapes get cleaned up.
Adds an Amp system plugin at ~/.config/amp/plugins/superset-lifecycle.ts
that bridges Amp's session.start / agent.start / agent.end events into
the existing notify hook. The wrapper now also exports SUPERSET_AGENT_ID
so the plugin's spawned notifier inherits Superset env context.

Registered as a new amp-plugin setup action that runs alongside the
existing amp-wrapper.
The linked-agent branch of PresetEditorDialog stacked an alert banner
on top of a read-only command field with two near-duplicate hints
('Edit the command in Agents settings' + 'Read-only — managed in
Agents settings'). Drops the banner and the second hint; replaces them
with a single inline 'Edit in <agent name>' link beside the Command
label. The muted mono command block carries the read-only signal on
its own. Missing/disabled-agent caption is preserved.
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