Commit Graph

402 Commits

  • Add todo hook companion to todo custom tool
    - /todos command displays all todos on current branch with custom UI
    - Update hooks.md to clarify components must not be wrapped in Box/Container
    - Cross-reference tool and hook in example READMEs
  • Update docs for ctx.ui.editor() and handoff example
    - Added ctx.ui.editor() to hooks.md and custom-tools.md
    - Added ctx.ui.editor() to CHANGELOG.md
    - Added handoff.ts to examples/hooks/README.md
  • fix(coding-agent): prevent full re-renders during write tool streaming
    Move line count from header to footer to avoid changing the first line
    during streaming, which was triggering full screen re-renders in the
    TUI's differential rendering logic.
  • Use serializeConversation in handoff hook
    Properly handles all message types including tool calls, thinking,
    and tool results instead of manual text extraction.
  • Add handoff example hook
    Transfers context to a new focused session instead of compacting.
    User provides a goal, hook generates a prompt with relevant context,
    creates a new session with parent tracking, and loads the prompt
    as a draft in the editor for review.
    
    Inspired by Amp's handoff feature.
  • Consolidate session events: remove session_before_new/session_new, add reason field to switch events
    - Remove session_before_new and session_new hook events
    - Add reason: 'new' | 'resume' to session_before_switch and session_switch events
    - Remove 'new' reason from custom tool onSession (use 'switch' for both /new and /resume)
    - Rename reset() to newSession(options?) in AgentSession
    - Add NewSessionOptions with optional parentSession for lineage tracking
    - Rename branchedFrom to parentSession in SessionHeader
    - Rename RPC reset command to new_session with optional parentSession
    - Update example hooks to use new event structure
    - Update documentation and changelog
    
    Based on discussion in #293
  • Add ctx.ui.theme getter for styling status text with theme colors
    - Add theme property to HookUIContext interface
    - Implement in interactive, RPC, and no-op contexts
    - Add status-line.ts example hook
    - Document styling with theme colors in hooks.md
  • Add setEditorText/getEditorText to hook UI context, improve custom() API
    - Add setEditorText() and getEditorText() to HookUIContext for prompt generator pattern
    - custom() now accepts async factories for fire-and-forget work
    - Add CancellableLoader component to tui package
    - Add BorderedLoader component for hooks with cancel UI
    - Export HookAPI, HookContext, HookFactory from main package
    - Update all examples to import from packages instead of relative paths
    - Update hooks.md and custom-tools.md documentation
    
    fixes #350
  • Change branch() to use entryId instead of entryIndex
    - AgentSession.branch(entryId: string) now takes entry ID
    - SessionBeforeBranchEvent.entryId replaces entryIndex
    - getUserMessagesForBranching() returns entryId
    - Update RPC types and client
    - Update UserMessageSelectorComponent
    - Update hook examples and tests
    - Update docs (hooks.md, sdk.md)
  • Update custom-compaction example to use serializeConversation
    Also fix docs to show convertToLlm is needed first.
  • Reorder execute params: (toolCallId, params, onUpdate, ctx, signal?)
    Optional signal now at the end for cleaner API
  • Rework custom tools API with CustomToolContext
    - CustomAgentTool renamed to CustomTool
    - ToolAPI renamed to CustomToolAPI
    - ToolContext renamed to CustomToolContext
    - ToolSessionEvent renamed to CustomToolSessionEvent
    - Added CustomToolContext parameter to execute() and onSession()
    - CustomToolFactory now returns CustomTool<any, any> for type compatibility
    - dispose() replaced with onSession({ reason: 'shutdown' })
    - Added wrapCustomTool() to convert CustomTool to AgentTool
    - Session exposes setToolUIContext() instead of leaking internals
    - Fix ToolExecutionComponent to sync with toolOutputExpanded state
    - Update all custom tool examples for new API
  • refactor(coding-agent): fix compaction for branched sessions, consolidate hook context types
    Compaction API:
    - prepareCompaction() now takes (pathEntries, settings) only
    - CompactionPreparation restructured: removed cutPoint/messagesToKeep/boundaryStart, added turnPrefixMessages/isSplitTurn/previousSummary/fileOps/settings
    - compact() now takes (preparation, model, apiKey, customInstructions?, signal?)
    - Fixed token overflow by using getPath() instead of getEntries()
    
    Hook types:
    - HookEventContext renamed to HookContext
    - HookCommandContext removed, RegisteredCommand.handler takes (args, ctx)
    - HookContext now includes model field
    - SessionBeforeCompactEvent: removed previousCompactions/model, added branchEntries
    - SessionBeforeTreeEvent: removed model (use ctx.model)
    - HookRunner.initialize() added for modes to set up callbacks
  • refactor(hooks): split session events into individual typed events
    Major changes:
    - Replace monolithic SessionEvent with reason discriminator with individual
      event types: session_start, session_before_switch, session_switch,
      session_before_new, session_new, session_before_branch, session_branch,
      session_before_compact, session_compact, session_shutdown
    - Each event has dedicated result type (SessionBeforeSwitchResult, etc.)
    - HookHandler type now allows bare return statements (void in return type)
    - HookAPI.on() has proper overloads for each event with correct typing
    
    Additional fixes:
    - AgentSession now always subscribes to agent in constructor (was only
      subscribing when external subscribe() called, breaking internal handlers)
    - Standardize on undefined over null throughout codebase
    - HookUIContext methods return undefined instead of null
    - SessionManager methods return undefined instead of null
    - Simplify hook exports to 'export type * from types.js'
    - Add detailed JSDoc for skipConversationRestore vs cancel
    - Fix createBranchedSession to rebuild index in persist mode
    - newSession() now returns the session file path
    
    Updated all example hooks, tests, and emission sites to use new event types.
  • Remove allowDuringStreaming flag - commands always run immediately
    Hook commands now always execute immediately, even during streaming.
    If a command needs to interact with the LLM, it uses pi.sendMessage()
    which handles queueing automatically.
    
    This simplifies the API and eliminates the issue of queued slash
    commands being sent to the LLM instead of executing.
  • WIP: Major cleanup - move Attachment to consumers, simplify agent API
    - Removed Attachment from agent package (now in web-ui/coding-agent)
    - Agent.prompt now takes (text, images?: ImageContent[])
    - Removed transports from web-ui (duplicate of agent package)
    - Updated coding-agent to use local message types
    - Updated mom package for new agent API
    
    Remaining: Fix AgentInterface.ts to compose UserMessageWithAttachments
  • Snake: add full border frame and pause/resume with session persistence
    - Full box border around title, game area, and instructions
    - ESC pauses and saves state to session via pi.appendEntry()
    - Resume shows 'PAUSED - press any key to continue'
    - Q quits and clears saved state
    - High score persists across games
  • Fix snake velocity: render cells as 2 chars wide for square aspect
    Terminal cells are ~2:1 aspect ratio, so movement appeared faster
    vertically. Now each game cell is 2 characters wide.
  • Improve snake game visuals
    - Rounded box corners (╭╮╰╯)
    - Better characters: ● head, ○ body, ◆ food, · empty
    - Colored title with emoji
    - Dimmed borders and help text
    - Bold highlights for score and controls
  • Add immediate flag to hook commands for non-queued execution
    Commands with immediate: true run right away even during streaming.
    Used for UI-only commands like /snake that don't interact with LLM.
  • Add ui.custom() for custom hook components with keyboard focus
    - Add custom() to HookUIContext: returns { close, requestRender }
    - Component receives keyboard input via handleInput()
    - CustomMessageComponent default rendering now limits to 5 lines when collapsed
    - Add snake.ts example hook with /snake command
  • Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext
    Breaking changes:
    - HookEventContext now has sessionManager and modelRegistry (moved from SessionEventBase)
    - HookAPI now has exec() method (moved from HookEventContext/HookCommandContext)
    - HookRunner constructor takes sessionManager and modelRegistry as required params
    - Session events no longer include sessionManager/modelRegistry fields
    
    Hook code migration:
    - event.sessionManager -> ctx.sessionManager
    - event.modelRegistry -> ctx.modelRegistry
    - ctx.exec() -> pi.exec()
    
    Updated:
    - src/core/hooks/types.ts - type changes
    - src/core/hooks/runner.ts - constructor, createContext
    - src/core/hooks/loader.ts - add exec to HookAPI
    - src/core/sdk.ts - pass sessionManager/modelRegistry to HookRunner
    - src/core/agent-session.ts - remove sessionManager/modelRegistry from events
    - src/modes/* - remove setSessionFile calls, update events
    - examples/hooks/* - update to new API
  • Hook API: replace send() with sendMessage(), add appendEntry() and registerCommand()
    Breaking changes to Hook API:
    - pi.send(text, attachments?) replaced with pi.sendMessage(message, triggerTurn?)
      - Creates CustomMessageEntry instead of user messages
      - Properly handles queuing during streaming via agent loop
      - Supports optional turn triggering when idle
    - New pi.appendEntry(customType, data?) for hook state persistence
    - New pi.registerCommand(name, options) for custom slash commands
    - Handler types renamed: SendHandler -> SendMessageHandler, new AppendEntryHandler
    
    Implementation:
    - AgentSession.sendHookMessage() handles all three cases:
      - Streaming: queues message with _hookData marker, agent loop processes it
      - Not streaming + triggerTurn: appends to state/session, calls agent.continue()
      - Not streaming + no trigger: appends to state/session only
    - message_end handler routes based on _hookData presence to correct persistence
    - HookRunner gains getRegisteredCommands() and getCommand() methods
    
    New types: HookMessage<T>, RegisteredCommand, CommandContext
  • Refactor SessionEventBase to pass sessionManager and modelRegistry
    Breaking changes to hook types:
    - SessionEventBase now passes sessionManager and modelRegistry directly
    - before_compact: passes preparation, previousCompactions (newest first)
    - before_switch: has targetSessionFile; switch: has previousSessionFile
    - Removed resolveApiKey (use modelRegistry.getApiKey())
    - getSessionFile() returns string | undefined for in-memory sessions
    
    Updated:
    - All session event emissions in agent-session.ts
    - Hook examples (custom-compaction.ts, auto-commit-on-exit.ts, confirm-destructive.ts)
    - Tests (compaction-hooks.test.ts, compaction-hooks-example.test.ts)
    - export-html.ts guards for in-memory sessions
  • Fix API key priority and compaction bugs
    - getEnvApiKey: ANTHROPIC_OAUTH_TOKEN now takes precedence over ANTHROPIC_API_KEY
    - findCutPoint: Stop scan-backwards loop at session header (was decrementing past it causing null preparation)
    - generateSummary/generateTurnPrefixSummary: Throw on stopReason=error instead of returning empty string
    - Test files: Fix API key priority order, use keepRecentTokens=1 for small test conversations
  • Session tree structure with id/parentId linking
    - Add TreeNode base type with id, parentId, timestamp
    - Add *Content types for clean input/output separation
    - Entry types are now TreeNode & *Content intersections
    - SessionManager assigns id/parentId on save, tracks leafId
    - Add migrateSessionEntries() for v1 to v2 conversion
    - Migration runs on load, rewrites file
    - buildSessionContext() uses tree traversal from leaf
    - Compaction returns CompactionResult (content only)
    - Hooks return compaction content, not full entries
    - Add firstKeptEntryId to before_compact hook event
    - Update mom package for tree fields
    - Better error messages for compaction failures
  • feat(coding-agent): Add --session-dir flag for custom session directory
    - Add --session-dir CLI flag to specify custom session directory
    - SessionManager API: second param of create(), continueRecent(), list(), open()
      changed from agentDir to sessionDir (direct directory, no cwd encoding)
    - When omitted, uses default (~/.pi/agent/sessions/<encoded-cwd>/)
    - --session now derives sessionDir from file's parent if --session-dir not provided
    - list() validates session header before processing files
    - Closes #313
    
    Co-authored-by: scutifer <scutifer@users.noreply.github.com>
  • Rename /clear to /new, update hook events to before_new/new
    Closes #305 - took direct rename approach instead of alias system
    
    Thanks @mitsuhiko for the nudge!
  • Refactor OAuth/API key handling: AuthStorage and ModelRegistry
    - Add AuthStorage class for credential storage (auth.json)
    - Add ModelRegistry class for model management with API key resolution
    - Add discoverAuthStorage() and discoverModels() discovery functions
    - Add migration from legacy oauth.json and settings.json apiKeys to auth.json
    - Remove configureOAuthStorage, defaultGetApiKey, findModel, discoverAvailableModels
    - Remove apiKeys from Settings type and SettingsManager methods
    - Rename getOAuthPath to getAuthPath
    - Update SDK, examples, docs, tests, and mom package
    
    Fixes #296
  • WIP: Remove global state from pi-ai OAuth/API key handling
    - Remove setApiKey, resolveApiKey, and global apiKeys Map from stream.ts
    - Rename getApiKey to getApiKeyFromEnv (only checks env vars)
    - Remove OAuth storage layer (storage.ts deleted)
    - OAuth login/refresh functions now return credentials instead of saving
    - getOAuthApiKey/refreshOAuthToken now take credentials as params
    - Add test/oauth.ts helper for ai package tests
    - Simplify root npm run check (single biome + tsgo pass)
    - Remove redundant check scripts from most packages
    - Add web-ui and coding-agent examples to biome/tsgo includes
    
    coding-agent still has compile errors - needs refactoring for new API
  • Add before/after session events with cancellation support
    - Merge branch event into session with before_branch/branch reasons
    - Add before_switch, before_clear, shutdown reasons
    - before_* events can be cancelled with { cancel: true }
    - Update RPC commands to return cancelled status
    - Add shutdown event on process exit
    - New example hooks: confirm-destructive, dirty-repo-guard, auto-commit-on-exit
    
    fixes #278
  • Fix SDK tools to respect cwd option
    Core tools now properly use the cwd passed to createAgentSession().
    Added tool factory functions for SDK users who specify custom cwd with explicit tools.
    
    Fixes #279
  • Add project-specific settings and SettingsManager factories
    - SettingsManager now loads .pi/settings.json from cwd (project settings)
    - Project settings merge with global settings (deep merge for objects)
    - Setters only modify global settings, project settings are read-only
    - Add static factories: SettingsManager.create(cwd?, agentDir?), SettingsManager.inMemory(settings?)
    - Add applyOverrides() for programmatic overrides
    - Replace 'settings' option with 'settingsManager' in CreateAgentSessionOptions
    - Update examples to use new pattern
    
    Incorporates PR #276 approach
  • Add SDK usage examples
    12 examples showing increasing levels of customization:
    - 01-minimal: all defaults
    - 02-custom-model: model and thinking level
    - 03-custom-prompt: replace or modify prompt
    - 04-skills: discover, filter, merge skills
    - 05-tools: built-in tools, custom tools
    - 06-hooks: logging, blocking, result modification
    - 07-context-files: AGENTS.md files
    - 08-slash-commands: file-based commands
    - 09-api-keys-and-oauth: API key resolution, OAuth config
    - 10-settings: compaction, retry, terminal settings
    - 11-sessions: persistence options
    - 12-full-control: replace everything
    
    Also exports FileSlashCommand type from index.ts
  • Convert custom tool examples to subdirectory/index.ts structure
    - hello.ts → hello/index.ts
    - question.ts → question/index.ts
    - todo.ts → todo/index.ts
    - subagent/subagent.ts → subagent/index.ts
  • Subagent: markdown rendering in expanded view, chain streaming shows all steps
    - Export getMarkdownTheme() from coding-agent for custom tools
    - Chain/parallel modes now use Markdown component in expanded view
    - Chain streaming updates include all previous steps (not just current)
    - Strip {previous} placeholder from task preview in renderCall
  • Refactor subagent tool, fix custom tool discovery, fix JSON mode stdout flush
    Breaking changes:
    - Custom tools now require index.ts entry point in subdirectory
      (e.g., tools/mytool/index.ts instead of tools/mytool.ts)
    
    Subagent tool improvements:
    - Refactored to use Message[] from ai package instead of custom types
    - Extracted agent discovery to separate agents.ts module
    - Added parallel mode streaming (shows progress from all tasks)
    - Added turn count to usage stats footer
    - Removed redundant Query section from scout output
    
    Fixes:
    - JSON mode stdout flush: Fixed race condition where pi --mode json
      could exit before all output was written, causing consumers to
      miss final events
    
    Also:
    - Added signal/timeout support to pi.exec() for custom tools and hooks
    - Renamed pi-pods bin to avoid conflict with pi