* fix(gmail): decode ISO-2022-JP bodies
* fix(gmail): include cc/bcc in get output
* feat(calendar): allow selecting calendars in events
* test(gmail): add edge case tests for ISO-2022-JP decoding
Add tests for edge cases in ISO-2022-JP body decoding:
- Mixed ASCII and Japanese text (e.g., "Hello こんにちは World")
- Empty content with ISO-2022-JP charset header
- Malformed ISO-2022-JP sequences (graceful degradation)
- Truncated escape sequences
These tests verify the graceful fallback behavior in decodeBodyCharset
which returns original data if decoding fails.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(calendar): validate unknown calendar names in resolveCalendarIDs
When a calendar name doesn't match any known calendar (not in bySummary
or byID maps), return an error listing the unrecognized names instead
of treating them as raw calendar IDs which causes cryptic Google API
errors.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(calendar): validate unknown and ambiguous calendar name resolutions
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(cli): improve agent ergonomics
* fix(cli): address code review findings
- Fix nil pointer dereference in confirmDestructive when flags is nil
- Deduplicate dry-run logic by delegating to dryRunExit
- Remove deprecated net.Error.Temporary() call (dead since Go 1.18)
- Add unit tests for resolveTasklistID and resolveCalendarID
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve PR #201 conflicts and follow-ups (#201) (thanks @salmonumbrella)
* fix: resolve rebase fallout for PR #201 landing (#201) (thanks @salmonumbrella)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Use tab-separated format like other gog commands:
attachment\t<filename>\t<size>\t<mimeType>\t<attachmentId>
This matches the pattern used in calendar_print.go (attendee, attachment)
and drive.go for array data.
Display attachment filename, size, MIME type, and attachment_id in both
plain text and JSON output for the 'gmail get' command with --format=full.
This makes it easier to identify and download attachments without needing
to manually parse the message payload structure.
Example plain text output:
attachments:
CV-Document.pdf (192123 bytes, application/pdf)
attachment_id ANGjdJ...
Example JSON output (new field):
"attachments": [
{"Filename": "CV-Document.pdf", "Size": 192123, ...}
]
Body extraction compared exact MIME types; parts often include params like
"text/plain; charset=utf-8", so multipart/alternative returned empty body
(null in JSON). Normalize MIME types (lowercase/trim/strip params) so
plain/html parts are found, preferring plain text. Also accept padded
base64url defensively.
* feat(gmail): add thread attachments command
Adds `gog gmail thread attachments <threadId>` command that lists all
attachments in an email thread with human-readable sizes.
Features:
- Lists attachments across all messages in a thread
- Shows filename, size (human-readable), and MIME type
- Optional --download flag to download all attachments
- Optional --out-dir to specify download directory
- Supports both JSON and text output formats
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(auth): check keychain before token import
Add pre-flight keychain accessibility check to AuthTokensImportCmd.Run
to fail early if the keychain is locked, rather than after the user has
already completed the import process.
Also adds the EnsureKeychainAccess function to the secrets package which
performs a write/delete test to verify keychain accessibility on macOS.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* style: group const declarations for gofumpt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address lint issues in store.go
- Wrap keychain access error for wrapcheck linter
- Add blank lines before returns for wsl linter
- Define static error for err113 linter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(cli): add mail and email aliases for gmail command
Enables `gog mail` and `gog email` as shortcuts for `gog gmail`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(gmail): add flattened headers to gmail get JSON output
Add a headers map with common email headers (from, to, cc, bcc, subject,
date) to the JSON output of `gog gmail get`. This makes header extraction
much simpler:
# Before (error-prone due to jq operator precedence)
jq '.message.payload.headers[] | select(.name == "To") | .value'
# After
jq '.headers.to'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(gmail): include inline attachments
* fix(secrets): dedupe keychain helpers
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>