---
phase: 15-telegram-inline-buttons
plan: 02
type: execute
wave: 2
depends_on: ["15-01"]
files_modified:
  - plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
autonomous: false
requirements: [BTN-01, BTN-02, BTN-03]

must_haves:
  truths:
    - "itermSessionId from notification JSON is parsed and passed to sendSessionNotification"
    - "transcriptPath is passed through to sendSessionNotification for button registration"
    - "swift build succeeds with all inline button changes"
  artifacts:
    - path: "plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift"
      provides: "Notification handler passes itermSessionId and transcriptPath to bot"
  key_links:
    - from: "main.swift"
      to: "TelegramBot.swift"
      via: "sendSessionNotification call with itermSessionId + transcriptPath params"
      pattern: "sendSessionNotification.*itermSessionId"
---

<objective>
Wire inline button support into the notification processing pipeline in main.swift and verify the full build compiles.

Purpose: Complete the integration by parsing itermSessionId from notification JSON files and passing it along with transcriptPath to the bot's sendSessionNotification, enabling the inline keyboard attachment and Focus Tab dedup.
Output: Modified main.swift, verified build
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/15-telegram-inline-buttons/15-01-SUMMARY.md
@plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift
@plugins/claude-tts-companion/Sources/claude-tts-companion/TelegramBot.swift

<interfaces>
<!-- From Plan 01 changes to TelegramBot.sendSessionNotification -->
The sendSessionNotification method now has additional parameters:
```swift
func sendSessionNotification(
    sessionId: String,
    turns: [ConversationTurn],
    cwd: String?,
    gitBranch: String?,
    startTime: Date?,
    lastActivity: Date?,
    itermSessionId: String?,    // NEW: for Focus Tab button + dedup
    transcriptPath: String?     // NEW: for button registration (Follow Up, Transcript)
) async
```

Legacy notification JSON (from stop hook) includes itermSessionId:

```json
{
  "sessionId": "...",
  "cwd": "...",
  "transcriptPath": "...",
  "itermSessionId": "optional-uuid-string"
}
```

The stop hook writes camelCase keys. Both `itermSessionId` and `iterm_session_id` should be checked (matching existing key-name fallback pattern in main.swift).
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Wire itermSessionId and transcriptPath into notification flow</name>
  <files>plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift</files>
  <read_first>
    - plugins/claude-tts-companion/Sources/claude-tts-companion/main.swift (lines 96-184, the NotificationWatcher handler)
    - plugins/claude-tts-companion/Sources/claude-tts-companion/TelegramBot.swift (sendSessionNotification signature after Plan 01)
  </read_first>
  <action>
Modify the NotificationWatcher callback in main.swift:

1. **Parse itermSessionId from notification JSON** — add after the existing cwd extraction (around line 116):

```swift
let itermSessionId = json["itermSessionId"] as? String ?? json["iterm_session_id"] as? String
```

This follows the exact same camelCase/snake_case fallback pattern used for sessionId and transcriptPath.

1. **Pass itermSessionId and transcriptPath to sendSessionNotification** — modify the call around line 173:

```swift
await bot.sendSessionNotification(
    sessionId: sessionId,
    turns: turns,
    cwd: cwd,
    gitBranch: gitBranch,
    startTime: entryStartTime,
    lastActivity: entryLastActivity,
    itermSessionId: itermSessionId,
    transcriptPath: tp
)
```

The `tp` variable (transcriptPath String) is already in scope from the `if let tp = transcriptPath` guard.

1. **Verify the build compiles** by running swift build after the change.
   </action>

  <verify>
    <automated>cd plugins/claude-tts-companion && swift build 2>&1 | tail -10</automated>
  </verify>
  <acceptance_criteria>
    - itermSessionId parsed from notification JSON with camelCase/snake_case fallback
    - transcriptPath passed through to sendSessionNotification
    - swift build succeeds with zero errors
  </acceptance_criteria>
  <done>Notification handler passes itermSessionId and transcriptPath to TelegramBot; full project compiles</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Verify inline buttons appear on notifications</name>
  <files>N/A</files>
  <action>
Human verification checkpoint. What was built:
Inline buttons on Arc Summary notifications: Focus Tab (iTerm2 tab switching), Follow Up (session resume prompt), Transcript (paginated transcript view). Focus Tab dedup removes buttons from older messages when new notification arrives for same iTerm tab.

Steps to verify:

1. Build: `cd plugins/claude-tts-companion && swift build -c release`
2. Run the companion binary (or restart the launchd service if deployed)
3. Trigger a session-end notification (close a Claude Code session or manually place a test .json in the notifications directory)
4. Check Telegram: the Arc Summary message should have three inline buttons: Focus Tab, Follow Up, Transcript
5. Tap "Focus Tab" — should switch to the iTerm2 tab (or show "Tab not found" if session ended)
6. Tap "Transcript" — should show a formatted transcript view
7. Trigger a second notification for the same iTerm tab — verify the first message's buttons are removed (dedup)

Resume signal: Type "approved" or describe issues
</action>
<verify>
<automated>cd plugins/claude-tts-companion && swift build -c release 2>&1 | tail -5</automated>
</verify>
<done>User confirms inline buttons appear on notifications and Focus Tab dedup works</done>
</task>

</tasks>

<verification>
1. `cd plugins/claude-tts-companion && swift build` succeeds
2. Notification JSON parsing extracts itermSessionId
3. sendSessionNotification receives itermSessionId and transcriptPath
4. Inline buttons visible on Telegram notifications (human verified)
</verification>

<success_criteria>

- swift build succeeds with all Phase 15 changes
- Arc Summary messages include inline keyboard buttons (BTN-01)
- Focus Tab button triggers iTerm2 tab switch via AppleScript (BTN-02)
- Focus Tab dedup removes old buttons when new notification arrives for same tab (BTN-03)
  </success_criteria>

<output>
After completion, create `.planning/phases/15-telegram-inline-buttons/15-02-SUMMARY.md`
</output>
