When OAuth refresh fails during model discovery, getApiKey() now returns
undefined instead of throwing. This allows the app to start and fall back
to other providers, so the user can /login to re-authenticate.
fixes#498
SettingsManager was created after extension loading, so extensions
defined in settings.json were never loaded. Move SettingsManager.create
before discoverAndLoadExtensions and merge settings extensions with
CLI --extension args.
- Auto-migrate commands/ to prompts/ on startup
- Warn if hooks/ or tools/ directories contain custom extensions
- Show deprecation warnings in interactive mode with keypress to continue
- Update CHANGELOG and docs with full migration guide
Breaking changes:
- Settings: 'hooks' and 'customTools' arrays replaced with 'extensions'
- CLI: '--hook' and '--tool' flags replaced with '--extension' / '-e'
- API: HookMessage renamed to CustomMessage, role 'hookMessage' to 'custom'
- API: FileSlashCommand renamed to PromptTemplate
- API: discoverSlashCommands() renamed to discoverPromptTemplates()
- Directories: commands/ renamed to prompts/ for prompt templates
Migration:
- Session version bumped to 3 (auto-migrates v2 sessions)
- Old 'hookMessage' role entries converted to 'custom'
Structural changes:
- src/core/hooks/ and src/core/custom-tools/ merged into src/core/extensions/
- src/core/slash-commands.ts renamed to src/core/prompt-templates.ts
- examples/hooks/ and examples/custom-tools/ merged into examples/extensions/
- docs/hooks.md and docs/custom-tools.md merged into docs/extensions.md
New test coverage:
- test/extensions-runner.test.ts (10 tests)
- test/extensions-discovery.test.ts (26 tests)
- test/prompt-templates.test.ts
* feat(coding-agent): add event bus for tool/hook communication
Adds pi.events API enabling custom tools and hooks to communicate via
pub/sub. Tools can emit events, hooks can listen. Shared EventBus instance
created per session in createAgentSession().
- EventBus interface with emit() and on() methods
- on() returns unsubscribe function
- Threaded through hook and tool loaders
- Documented in hooks.md and custom-tools.md
* fix(coding-agent): wrap event handlers to catch errors
* docs: note async handler error handling for event bus
* feat(coding-agent): add sendMessage to tools, nextTurn delivery mode
- Custom tools now have pi.sendMessage() for direct agent notifications
- New deliverAs: 'nextTurn' queues messages for next user prompt
- Fix: hooks and tools now share the same eventBus (was isolated before)
* fix(coding-agent): nextTurn delivery should always queue, even when streaming
Hook API additions:
- pi.getTools() / pi.setTools(toolNames) - dynamically enable/disable tools
- pi.registerFlag(name, options) / pi.getFlag(name) - register custom CLI flags
- pi.registerShortcut(shortcut, options) - register keyboard shortcuts
Plan mode hook (examples/hooks/plan-mode.ts):
- /plan command or Shift+P shortcut to toggle
- --plan CLI flag to start in plan mode
- Read-only tools: read, bash, grep, find, ls
- Bash restricted to non-destructive commands (blocks rm, mv, git commit, etc.)
- Interactive prompt after each response: execute, stay, or refine
- Shows plan indicator in footer when active
- State persists across sessions
- Add tree sidebar with search and filter (Default/All/Labels)
- Client-side markdown/syntax highlighting via vendored marked.js + highlight.js
- Base64 encode session data to avoid escaping issues
- Reuse theme.ts color tokens via getResolvedThemeColors()
- Sticky sidebar, responsive mobile layout with overlay
- Click tree node to scroll to message
- Keyboard shortcuts: Esc to reset, Ctrl/Cmd+F to search
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.
- 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
- Create migrations.ts with consolidated migrations
- Move auth migration from AuthStorage.migrateLegacy() to migrations.ts
- Add migrateSessionsFromAgentRoot() to fix misplaced sessions
- Sessions in ~/.pi/agent/*.jsonl are auto-migrated on startup
fixes#320
- 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>
- 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
- 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
- loadAndMergeModels(agentDir) - loads models.json from agentDir
- getAvailableModels(agentDir) - uses agentDir for model discovery
- findModel(provider, id, agentDir) - uses agentDir for model lookup
- configureOAuthStorage(agentDir) - configures OAuth to use agentDir/oauth.json
- createAgentSession calls configureOAuthStorage with options.agentDir
- Export configureOAuthStorage from SDK
- Add factory methods: create(cwd), open(path), continueRecent(cwd), inMemory()
- Add static list(cwd) for session listing
- Make constructor private, pass cwd explicitly
- Update SDK to take sessionManager instead of sessionFile options
- Update main.ts to create SessionManager based on CLI flags
- Update SessionSelectorComponent to take sessions[] instead of SessionManager
- Update tests to use factory methods
- Add continueSession, restoreFromSession, additionalHookPaths,
additionalCustomToolPaths, scopedModels to CreateAgentSessionOptions
- Return CreateAgentSessionResult with session, customToolsResult,
and modelFallbackMessage
- main.ts now focuses on CLI arg parsing and mode routing
- Reduced main.ts from ~490 to ~340 lines
Adds glob pattern support for skill filtering:
- --skills <patterns> CLI flag (comma-separated glob patterns)
- includeSkills setting in settings.json
- ignoredSkills now supports glob patterns
- ignoredSkills takes precedence over includeSkills and --skills
Closes#268
- Add setOAuthStorage() and resetOAuthStorage() to pi-ai for custom storage backends
- Configure coding-agent to use its own configurable OAuth path via getOAuthPath()
- Model selector (/model command) now only shows models from --models scope when set
- Rewrite OAuth documentation in pi-ai README with examples
Fixes#255
- setThinkingLevel() now clamps xhigh to high when model doesn't support it
- Model changes automatically re-clamp the current thinking level
- Fixed /model command to use session.setModel() instead of agent.setModel()
- Footer and editor border color update after model/thinking changes
Closes#253
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
- Custom tools: TypeScript modules that extend pi with new tools
- Custom TUI rendering via renderCall/renderResult
- User interaction via pi.ui (select, confirm, input, notify)
- Session lifecycle via onSession callback for state reconstruction
- Examples: todo.ts, question.ts, hello.ts
- Hook examples: permission-gate, git-checkpoint, protected-paths
- Session lifecycle centralized in AgentSession
- Works across all modes (interactive, print, RPC)
- Unified session event for hooks (replaces session_start/session_switch)
- Box component added to pi-tui
- Examples bundled in npm and binary releases
Fixes#190
* Add skills system with Claude Code compatibility
* consolidate skills into single module, merge loaders, add <available_skills> XML tags
* add Codex CLI skills compatibility, skip hidden/symlinks
- Parse --version and -v flags in args.ts
- Handle version flag early in main.ts (print and exit)
- Add flag to help text
- Add comprehensive test coverage for CLI arg parsing
Co-authored-by: cc-vps <crcatala+vps@gmail.com>
The theme file watcher was keeping the Node.js process alive indefinitely
even in print mode where hot-reload is unnecessary. This simple fix calls
stopThemeWatcher() and process.exit(0) after print mode completes.
- Added stopThemeWatcher() call after runPrintMode() completes
- Added process.exit(0) to ensure clean process termination
- Imported stopThemeWatcher from theme module
This is a minimal fix that addresses the symptom (process hanging) without
changing the theme initialization logic.
The theme file watcher was keeping the Node.js process alive indefinitely
even in print mode where hot-reload is unnecessary. This fix adds an
enableWatcher parameter to initTheme() and setTheme() functions, and only
enables watchers in interactive mode.
- Modified initTheme() to accept enableWatcher parameter (default: false)
- Modified setTheme() to accept enableWatcher parameter (default: false)
- Updated main.ts to only enable watchers in interactive mode
- Updated InteractiveMode to enable watchers when changing themes