Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions docs/ai/design/2026-06-04-feature-agent-console-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
phase: design
title: Agent Console Channel Controls Design
description: TUI architecture for Telegram daemon channel controls
---

# Agent Console Channel Controls Design

## Architecture Overview

```mermaid
graph TD
User[User presses c or C]
Shell[ConsoleAppShell]
Picker[ChannelSelectPane]
Action[runAction]
CLI[Current CLI entry]
Config[(~/.ai-devkit/channels.json)]
Start[channel start selected-channel --agent name --daemon]
Stop[channel stop connected-channel]
ChannelService[ChannelService]
Registry[(~/.ai-devkit/channel-bridges.json)]
Context[ConsoleProvider]
AgentList[AgentListPane]
Preview[PreviewPane]

User --> Shell
Shell --> Picker
Picker --> Action
Action --> CLI
CLI --> Start
CLI --> Stop
Start --> ChannelService
Stop --> ChannelService
ChannelService --> Registry
Context --> Config
Context --> ChannelService
Context --> AgentList
Context --> Preview
```

The console reads live channel bridge metadata with the existing `ChannelService` and reads configured channels through `ConfigStore`, which points at `~/.ai-devkit/channels.json`. It does not parse registry or config files directly. Start and stop remain subprocess actions routed through `runAction`, matching the existing console pattern for agent start/open/send/rename/kill behavior.

## Data Models

```typescript
interface ChannelBridgeProcess {
channelName: string;
channelType: string;
agentName: string;
agentPid: number;
bridgePid: number;
startedAt: string;
logPath?: string;
}

interface AgentChannelStatus {
channelName: string;
channelType: string;
bridgePid: number;
}

type AgentChannelStatusMap = Record<string, AgentChannelStatus>;

interface ConfiguredChannel {
name: string;
type: string;
enabled: boolean;
botUsername?: string;
}

type ConsoleAction =
| ExistingConsoleAction
| { type: 'channel-start'; agentName: string; channelName: string }
| { type: 'channel-stop'; channelName: string };
```

The status map is keyed by `agentName` because existing bridge metadata records the agent name and the console selection/actions are name-driven.

## API Design

### Console Context

Expose channel state alongside agent state:

```typescript
interface ConsoleContextValue {
channelStatuses: AgentChannelStatusMap;
refreshChannels(): Promise<void>;
configuredChannels: ConfiguredChannel[];
refreshConfiguredChannels(): Promise<void>;
}
```

`useChannelState` creates a `ChannelService`, calls `getLiveBridges()`, converts results into the status map, and refreshes status after successful channel actions. It also creates a `ConfigStore`, calls `getConfig()`, and exposes non-secret configured channel metadata for the selector. `ConsoleProvider` combines this channel state with the existing agent list context.

### Action Runner

Add channel actions to the existing argv builder:

```typescript
case 'channel-start':
return ['channel', 'start', action.channelName, '--agent', action.agentName, '--daemon'];
case 'channel-stop':
return ['channel', 'stop', action.channelName];
```

Values are passed as argv entries to `spawn`; no shell interpolation is introduced.

### UI Components

- `ConsoleAppShell`: handles `c` and `C` when no text input owns keyboard focus.
- `useChannelActions`: owns channel selector/start/stop action orchestration and transient messages.
- `useChannelState`: owns configured channel and live bridge state loading.
- `ChannelSelectPane`: right-pane selector for channels configured in `~/.ai-devkit/channels.json`.
- `AgentListPane`: receives `channelStatuses` and shows a compact `remote` marker beside connected agents.
- `PreviewPane`: receives selected agent channel status and switches border color to green when connected.
- `PreviewPane`: renders status text such as `Connected: <channel-name>`.
- `StatusFooter`/`HelpPane`: document `c channel` and `C stop channel`.

## Component Breakdown

| Component | Change |
|---|---|
| `packages/cli/src/tui/console/actions/types.ts` | Add channel start/stop action types |
| `packages/cli/src/tui/console/actions/runAction.ts` | Map channel actions to existing CLI commands |
| `packages/cli/src/tui/console/state/ConsoleContext.tsx` | Expose agent list plus channel state |
| `packages/cli/src/tui/console/hooks/useChannelState.ts` | Load configured channels and live bridge status |
| `packages/cli/src/tui/console/hooks/useChannelActions.ts` | Open selector and run channel start/stop actions |
| `packages/cli/src/tui/console/ConsoleApp.tsx` | Route `c`/`C` shortcuts and render channel selector workspace |
| `packages/cli/src/tui/console/ChannelSelectPane.tsx` | New native Ink right-pane workspace for choosing configured channel |
| `packages/cli/src/tui/console/AgentListPane.tsx` | Render `remote` marker for connected agents |
| `packages/cli/src/tui/console/PreviewPane.tsx` | Green border and connected status text |
| `packages/cli/src/tui/console/StatusFooter.tsx` | Add shortcut hints |
| `packages/cli/src/tui/console/HelpPane.tsx` | Add channel shortcut documentation |
| `packages/cli/src/__tests__/tui/console/**` | Cover action argv and render states |

## Design Decisions

### Use Daemon Commands

The console starts channels with `--daemon` because foreground bridges are long-running. This keeps the TUI responsive and delegates process management to the existing channel daemon service.

### Use Existing ChannelService for Status

The TUI should not parse `~/.ai-devkit/channel-bridges.json` directly. `ChannelService.getLiveBridges()` already owns stale process handling and registry conventions.

### Select From Configured Channels

The console supports multiple configured channels by reading `~/.ai-devkit/channels.json` through `ConfigStore`. `c` opens a selector instead of hardcoding `telegram`.

### Agent Name Keying

The console already sends actions by agent name, and bridge metadata stores `agentName`. Keying the status map by name avoids coupling UI state to PID matching rules.

## Non-Functional Requirements

- Channel state refresh must not block rendering or agent list polling.
- Start/stop commands must pipe stdio like existing console actions.
- Visual indicators must remain compact in narrow terminals.
- The preview green border should use the existing design-system color vocabulary where available.
- Channel metadata surfaced in the UI must not include secrets.
69 changes: 69 additions & 0 deletions docs/ai/implementation/2026-06-04-feature-agent-console-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
phase: implementation
title: Agent Console Channel Controls Implementation
description: Implementation notes and verification evidence for console channel controls
---

# Agent Console Channel Controls Implementation

## Development Setup

- Worktree: `.worktrees/feature-agent-console-channel`
- Branch: `feature-agent-console-channel`
- Dependencies installed with `npm ci`.
- Worktree bootstrap note: npm completed successfully; Husky could not update parent `.git/config` from the sandbox, but dependencies were installed.

## Code Structure

- `packages/cli/src/tui/console/actions/types.ts`: channel start/stop action types.
- `packages/cli/src/tui/console/actions/runAction.ts`: argv mapping for `channel start <name> --agent <agent> --daemon` and `channel stop <name>`.
- `packages/cli/src/tui/console/state/ConsoleContext.tsx`: combines agent list state with channel state for console consumers.
- `packages/cli/src/tui/console/hooks/useChannelState.ts`: live bridge status and configured channel metadata loading.
- `packages/cli/src/tui/console/hooks/useChannelActions.ts`: channel selector/start/stop action orchestration.
- `packages/cli/src/tui/console/ChannelSelectPane.tsx`: right-pane configured-channel selector.
- `packages/cli/src/tui/console/ConsoleApp.tsx`: `c` opens selector, `C` stops selected agent's connected channel.
- `packages/cli/src/tui/console/AgentListPane.tsx`: connected channel `remote` marker.
- `packages/cli/src/tui/console/PreviewSection.tsx` and `PreviewPane.tsx`: green border and `Connected: <channel-name>` status.
- `packages/cli/src/tui/console/HelpPane.tsx`: footer/help shortcut text.

## Implementation Notes

- Channel start is always daemonized from the console.
- Configured channels are loaded via `ConfigStore.getConfig()` from `~/.ai-devkit/channels.json`.
- Only non-secret channel metadata reaches the TUI: name, type, enabled state, and bot username.
- Live channel status is loaded via `ChannelService.getLiveBridges()` so stale bridge cleanup remains owned by the existing service.
- `C` stops the channel connected to the currently selected agent; if the selected agent is not connected, the console shows an error instead of guessing.
- Simplification pass extracted channel polling and channel action flows into focused hooks so `ConsoleContext` and `ConsoleApp` stay closer to the existing console patterns.
- React best-practices check: channel polling pauses while chat input is focused, matching `useAgentList`; channel status/config state updates are skipped when polled data is unchanged.

## Error Handling

- Start/stop subprocess failures surface stderr or exit-code fallback text in the console transient message area.
- Channel config/status refresh failures clear local TUI channel state rather than crashing the provider.
- The selector shows a no-channels message when `channels.json` has no configured channels.

## Verification Evidence

- `npx ai-devkit@latest lint --feature agent-console-channel`: passed.
- `npm test -- src/__tests__/tui/console/actions/runAction.test.ts src/__tests__/tui/console/channelStatus.test.ts src/__tests__/tui/console/ChannelSelectPane.test.ts`: 3 files, 16 tests passed.
- `npm test -- src/__tests__/tui/console/hooks/useChannelActions.test.ts`: 1 file, 7 tests passed.
- `npm test -- src/__tests__/tui/console/channelStatus.test.ts`: 1 file, 7 tests passed.
- `npm test -- src/__tests__/tui/console`: 15 files, 95 tests passed.
- `npm run build --workspace packages/cli`: passed after compiling 146 files.
- `npm run lint --workspace packages/cli`: exit 0 with 5 existing warnings in unrelated files.
- `npm test --workspace packages/cli -- --testTimeout=15000`: 55 files, 694 tests passed.
- Coverage command `npm test --workspace packages/cli -- --coverage src/__tests__/tui/console` is blocked by Vitest failing to resolve `@vitest/coverage-v8` from the root `node_modules` path.

## Phase 6 Implementation Check

- Requirements alignment: implemented `c` selector from configured channels, daemon start, `C` stop for the selected agent's connected channel, live bridge refresh, connected list marker, green preview border, and connected channel status text.
- Design alignment: start/stop remain routed through `runAction`; configured channels are read through `ConfigStore`; live bridge state is read through `ChannelService`; no token or secret fields are exposed to TUI components.
- Deliberate UI wording: the list uses a terminal-safe ASCII `remote` marker instead of an emoji icon so it renders consistently across terminal types.
- No blocking deviations found.

## Phase 8 Code Review

- Findings: no blocking correctness, integration, security, or React render-stability issues remain after the channel polling pause/equality fixes.
- Security review scope: no shell interpolation introduced; channel/agent values are passed as argv entries to `spawn`; TUI channel metadata excludes bot tokens and other secrets.
- Integration review scope: channel start/stop uses existing `channel start <name> --agent <agent> --daemon` and `channel stop <name>` command contracts; `ChannelService` and `ConfigStore` remain the source of truth for live bridge/config state.
- Final verification: full CLI suite passed with 55 files and 698 tests; CLI build passed; CLI lint exited 0 with the existing 5 unrelated warnings; feature lint passed; `git diff --check` passed.
69 changes: 69 additions & 0 deletions docs/ai/planning/2026-06-04-feature-agent-console-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
phase: planning
title: Agent Console Channel Controls Plan
description: Task breakdown for Telegram daemon controls in agent console
---

# Agent Console Channel Controls Plan

## Milestones

- [x] Milestone 1: Console actions and channel status state are wired.
- [x] Milestone 2: Agent list and preview render connected indicators.
- [x] Milestone 3: Shortcut UX, tests, and documentation updates are complete.

## Task Breakdown

### Phase 1: Foundation
- [x] Task 1.1: Add channel start/stop action types.
- [x] Task 1.2: Extend `runAction` argv mapping for `channel start <channel-name> --agent <name> --daemon` and `channel stop <channel-name>`.
- [x] Task 1.3: Add channel status loading/refresh support to console context using `ChannelService.getLiveBridges()`.
- [x] Task 1.4: Add configured-channel loading from `~/.ai-devkit/channels.json` through `ConfigStore`.

### Phase 2: UI Indicators
- [x] Task 2.1: Pass channel status into `AgentListPane` and render connected icon.
- [x] Task 2.2: Pass selected agent channel status into `PreviewPane`.
- [x] Task 2.3: Render green connected preview border and `Connected: <channel-name>` status.

### Phase 3: Shortcuts and Feedback
- [x] Task 3.1: Handle `c` and `C` shortcuts in `ConsoleAppShell` outside text-input modes.
- [x] Task 3.2: Refresh channel status after successful start/stop.
- [x] Task 3.3: Surface start/stop success and error messages.
- [x] Task 3.4: Update footer/help shortcut text.
- [x] Task 3.5: Add right-pane channel selector for configured channels.

### Phase 4: Tests and Verification
- [x] Task 4.1: Add/extend action runner tests for channel actions.
- [x] Task 4.2: Add/extend component tests for agent-list icon and preview connected state.
- [x] Task 4.3: Add/extend shell/context tests for shortcut action dispatch and refresh behavior where practical.
- [x] Task 4.4: Run feature lint, targeted tests, and build/type checks relevant to CLI.

## Implementation Summary

Implemented multi-channel console controls. `c` opens a right-pane selector populated from `~/.ai-devkit/channels.json` through `ConfigStore`; selecting a channel starts `channel start <channel> --agent <selected-agent> --daemon`. `C` stops the channel connected to the selected agent. Connected agents show a channel icon in the agent list, a green preview border, and `Connected: <channel-name>` status text.

## Dependencies

- Existing `channel start --daemon` and `channel stop` implementation.
- Existing `ChannelService.getLiveBridges()` stale-state handling.
- Existing console action runner and Ink component test patterns.

## Timeline & Estimates

- Phase 1: 1-2 hours.
- Phase 2: 1-2 hours.
- Phase 3: 1-2 hours.
- Phase 4: 1-2 hours.

## Risks & Mitigation

- Risk: Channel service reads user-global state during tests. Mitigation: mock `ChannelService` or inject a service instance.
- Risk: Uppercase `C` collides with text input. Mitigation: preserve existing focus/mode guards before shortcut handling.
- Risk: Green border token does not exist. Mitigation: use the existing success/accent token if available, otherwise add a minimal token-consistent value.
- Risk: Multiple configured Telegram channels. Mitigation: v1 uses the explicit default name `telegram`; future work can add selection.

## Resources Needed

- Existing CLI/TUI code and Jest test setup.
- Existing channel daemon docs and service implementation.
- Optional real Telegram bot credentials for manual end-to-end validation.
Loading
Loading