co-mono/packages/coding-agent/DEVELOPMENT.md

9 KiB

coding-agent Development Guide

This document describes the architecture and development workflow for the coding-agent package.

Architecture Overview

The coding-agent is structured into distinct layers:

┌─────────────────────────────────────────────────────────────┐
│                         CLI Layer                           │
│  cli.ts → main.ts → cli/args.ts, cli/file-processor.ts     │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                       Mode Layer                            │
│  modes/interactive/   modes/print-mode.ts   modes/rpc-mode.ts │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                       Core Layer                            │
│  core/agent-session.ts (central abstraction)               │
│  core/session-manager.ts, core/model-config.ts, etc.       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   External Dependencies                     │
│  @mariozechner/pi-agent-core (Agent, tools)                │
│  @mariozechner/pi-ai (models, providers)                   │
│  @mariozechner/pi-tui (TUI components)                     │
└─────────────────────────────────────────────────────────────┘

Directory Structure

src/
├── cli.ts                    # CLI entry point (shebang, calls main)
├── main.ts                   # Main orchestration, argument handling, mode routing
├── index.ts                  # Public API exports

├── cli/                      # CLI-specific utilities
│   ├── args.ts               # parseArgs(), printHelp(), Args interface
│   ├── file-processor.ts     # processFileArguments() for @file args
│   └── session-picker.ts     # selectSession() TUI for --resume

├── core/                     # Core business logic (mode-agnostic)
│   ├── agent-session.ts      # AgentSession class - THE central abstraction
│   ├── bash-executor.ts      # executeBash() with streaming, abort
│   ├── compaction.ts         # Context compaction logic
│   ├── export-html.ts        # exportSession(), exportFromFile()
│   ├── messages.ts           # BashExecutionMessage, messageTransformer
│   ├── model-config.ts       # findModel(), getAvailableModels(), getApiKeyForModel()
│   ├── model-resolver.ts     # resolveModelScope(), restoreModelFromSession()
│   ├── session-manager.ts    # SessionManager class - JSONL persistence
│   ├── settings-manager.ts   # SettingsManager class - user preferences
│   ├── slash-commands.ts     # loadSlashCommands() from ~/.pi/agent/commands/
│   ├── system-prompt.ts      # buildSystemPrompt(), loadProjectContextFiles()
│   ├── oauth/                # OAuth authentication (Anthropic, etc.)
│   │   ├── anthropic.ts
│   │   ├── storage.ts
│   │   └── index.ts
│   └── tools/                # Tool implementations
│       ├── bash.ts, edit.ts, find.ts, grep.ts, ls.ts, read.ts, write.ts
│       ├── truncate.ts       # Output truncation utilities
│       └── index.ts          # Tool exports, allTools, codingTools

├── modes/                    # Run mode implementations
│   ├── index.ts              # Re-exports InteractiveMode, runPrintMode, runRpcMode
│   ├── print-mode.ts         # Non-interactive: process messages, print output, exit
│   ├── rpc-mode.ts           # JSON-RPC mode for programmatic control
│   └── interactive/          # Interactive TUI mode
│       ├── interactive-mode.ts   # InteractiveMode class
│       ├── components/           # TUI components (editor, selectors, etc.)
│       │   ├── assistant-message.ts
│       │   ├── bash-execution.ts
│       │   ├── custom-editor.ts
│       │   ├── footer.ts
│       │   ├── model-selector.ts
│       │   ├── session-selector.ts
│       │   └── ... (other selectors)
│       └── theme/
│           ├── theme.ts      # Theme loading, getEditorTheme(), etc.
│           ├── dark.json
│           ├── light.json
│           └── theme-schema.json

└── utils/                    # Generic utilities
    ├── changelog.ts          # parseChangelog(), getNewEntries()
    ├── clipboard.ts          # copyToClipboard()
    ├── config.ts             # APP_NAME, VERSION, paths (getAgentDir, etc.)
    ├── fuzzy.ts              # Fuzzy string matching
    ├── shell.ts              # getShellConfig()
    └── tools-manager.ts      # ensureTool() - download fd, etc.

Key Abstractions

AgentSession (core/agent-session.ts)

The central abstraction that wraps the low-level Agent with:

  • Session persistence (via SessionManager)
  • Settings persistence (via SettingsManager)
  • Model cycling with scoped models
  • Context compaction
  • Bash command execution
  • Message queuing

All three modes (interactive, print, rpc) use AgentSession.

InteractiveMode (modes/interactive/interactive-mode.ts)

Handles TUI rendering and user interaction:

  • Subscribes to AgentSession events
  • Renders messages, tool executions, streaming
  • Manages editor, selectors, key handlers
  • Delegates all business logic to AgentSession

SessionManager (core/session-manager.ts)

Handles session persistence:

  • JSONL format for append-only writes
  • Session file location management
  • Message loading/saving
  • Model/thinking level persistence

SettingsManager (core/settings-manager.ts)

Handles user preferences:

  • Default model/provider
  • Theme selection
  • Queue mode
  • Thinking block visibility

Development Workflow

Running in Development

# From monorepo root
npx tsx packages/coding-agent/src/cli.ts

# With arguments
npx tsx packages/coding-agent/src/cli.ts --help
npx tsx packages/coding-agent/src/cli.ts -p "Hello"

Type Checking

# From monorepo root
npm run check

Building

# Build all packages
npm run build

# Build standalone binary
cd packages/coding-agent
npm run build:binary

Adding New Features

Adding a New Slash Command

  1. If it's a UI-only command (e.g., /theme), add handler in interactive-mode.ts setupEditorSubmitHandler()
  2. If it needs session logic, add method to AgentSession and call from mode

Adding a New Tool

  1. Create tool in core/tools/ following existing patterns
  2. Export from core/tools/index.ts
  3. Add to allTools and optionally codingTools
  4. Add description to toolDescriptions in core/system-prompt.ts

Adding a New Selector

  1. Create component in modes/interactive/components/
  2. Use showSelector() helper in interactive-mode.ts:
private showMySelector(): void {
    this.showSelector((done) => {
        const selector = new MySelectorComponent(
            // ... params
            (result) => {
                // Handle selection
                done();
                this.showStatus(`Selected: ${result}`);
            },
            () => {
                done();
                this.ui.requestRender();
            },
        );
        return { component: selector, focus: selector.getSelectList() };
    });
}

Testing

The package uses E2E tests only (no unit tests by design). Tests are in test/:

# Run tests
npm test

Code Style

  • No any types unless absolutely necessary
  • No inline dynamic imports
  • Use showStatus() for dim status messages
  • Use showError() / showWarning() for errors/warnings
  • Keep InteractiveMode focused on UI, delegate logic to AgentSession