openplanr 0.5.0
Added
Secure credential storage — API keys are now stored in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) via
@napi-rs/keyring, with AES-256-GCM encrypted file fallback for environments without a keychain (CI, Docker, SSH)Automatic credential migration — existing plaintext
~/.planr/credentials.jsonkeys are migrated to the secure backend on first access, then the plaintext file is deletedCredential source display —
openplanr config shownow shows where the API key is stored:(OS keychain),(encrypted file), or(env: ANTHROPIC_API_KEY)Per-command token budgets — each command uses a tuned
maxTokenslimit (epic: 4K, feature/story/refine: 8K, task: 16K, task --feature: 32K) instead of a one-size-fits-all defaultDefinitive truncation detection — uses
stop_reason(Anthropic) /finish_reason(OpenAI) to detect truncated responses instead of heuristic token thresholds8 new truncation unit tests covering skip-retry, per-attempt token reporting, and streaming truncation
Changed
openplanr config set-keynow shows the storage backend:"saved to OS keychain"or"saved to encrypted file"AI service refactored —
generateJSONandgenerateStreamingJSONnow share a commongenerateCore()function, eliminating duplicated validation/retry/truncation logicGitHub Actions updated to v6 (checkout, setup-node) and v7 (upload-artifact) with Node.js 24
Fixed
Task generation from features failing —
openplanr task create --featurewas truncating AI responses at 4,096 tokens, producing invalid JSON. Now uses 32K budgetSpinner not stopping on API errors — spinner animation no longer mixes with error messages when the AI provider throws
Spinner showing ✓ before validation —
succeed()now only fires after successful parse/validation, not beforeTruncation error over-reporting tokens — error messages now show per-attempt output tokens instead of cumulative totals
Keychain write failures crashing —
saveCredentialnow catches keychain errors and falls back to encrypted fileMigration flag set before completion —
migrateCredentialsnow resets the flag on failure so it retries next invocationresolveApiKeySourceskipping migration —config shownow properly triggers legacy credential migration
Security
API keys no longer stored in plaintext on disk
Encrypted file uses AES-256-GCM with machine-derived key (hostname + username + per-installation salt via scrypt)
File permissions set to
0o600on all credential files
Developer Experience
Test coverage: 261 → 269 tests across 23 test files
Added
tests/unit/ai-service-truncation.test.ts(8 tests)Added
tests/unit/credential-backends.test.ts(8 tests)Expanded
tests/unit/credentials-service.test.tswith mocked backends (13 tests)