content: string | (TextContent | ImageContent)[]
This matches the UserMessage type from pi-ai, so content can be
passed directly to AppMessage without conversion.
- CustomMessageEntry<T> type with customType, content, display, details
- appendCustomMessageEntry() in SessionManager
- buildSessionContext() includes custom_message entries as user messages
- Exported CustomEntry and CustomMessageEntry from main index
CustomEntry is for hook state (not in context).
CustomMessageEntry is for hook-injected content (in context).
- CompactionEntry<T> and CompactionResult<T> now have optional details?: T
- appendCompaction() accepts optional details parameter
- Hooks can return compaction.details to store custom data
- Enables structured compaction with ArtifactIndex (see #314)
- Fix CompactionResult export location (now from compaction.ts)
- Update plan with remaining compaction refactor items
- Import CompactionResult in hooks/types.ts
- Replace inline type with CompactionResult for SessionEventResult.compaction
- Add labels feature to changelog
- Add LabelEntry type with targetId and label (string | undefined)
- Add labelsById map built on load via linear scan
- Add getLabel(id) and appendLabelChange(targetId, label) methods
- Add label field to SessionTreeNode, populated by getTree()
- Update createBranchedSession to preserve labels for entries on path
- Labels are ignored by buildSessionContext (not sent to LLM)
- Add comprehensive tests for label functionality
- Replace custom uuidv4() with native crypto.randomUUID()
- Entry IDs use first 8 hex chars with collision checking
- Session IDs stay full UUIDs (used in filenames)
- ~0.01 collisions per 10k entries, retry handles it
When --session path was provided for a non-existent file, _initNewSession() was overwriting the path with an auto-generated one. Now it only generates a filename if sessionFile wasn't already set.
- SessionEntry now only contains conversation entries (messages, compaction, etc.)
- SessionHeader is separate, not part of SessionEntry
- FileEntry = SessionHeader | SessionEntry (for file storage)
- getEntries() filters out header, returns SessionEntry[]
- Added getHeader() for accessing session metadata
- Updated compaction and tests to not expect header in entries
- Updated mom package to use FileEntry for internal storage
- 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
Use OSC 8 hyperlink escape sequence to show 'Click here to login'
as a clickable link instead of displaying the raw URL which spans
multiple lines and is hard to click in terminals (especially WSL).
The bash tool is named "bash" and described as executing bash commands,
but was using sh on Unix. On many distros (Ubuntu, Debian, Alpine, etc.),
/bin/sh is a POSIX-only shell that doesn't support bash syntax like [[ ]],
arrays, or here-strings. This caused the LLM to write bash syntax that
failed, wasting tokens on rewrites.
Now prefers /bin/bash on Unix, falling back to sh only if bash isn't found.
- pi install <type> <source> (global default, -p for project)
- pi remove <type> <name>
- pi update [types...]
- Install adds to settings.json + installs to disk
- Global is default, -p/--project for project-local
Unified system for loading hooks, tools, skills, and themes from:
- Local files and directories
- npm packages (npm:pkg@version)
- Git repositories (git:url@tag or git:url#branch)
Includes filtering, atomic installation, and settings hierarchy.
- 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>