Add OPENCODE_CLI_RUN_MODE environment variable check to skip all startup
toasts and version checks when running in CLI mode. This prevents
notification spam during automated CLI run sessions.
Includes comprehensive test coverage for CLI run mode behavior.
🤖 Generated with OhMyOpenCode assistance
- getSdkMessages now handles both response.data and direct array
responses from SDK
- Consolidated getMessageDir: storage.ts now re-exports from shared
opencode-message-dir.ts (with path traversal guards)
- Replace all response.data ?? [] with (response.data ?? response)
pattern across 14 files to handle SDK array-shaped responses
- Normalize SDK parts in parts-reader.ts by injecting sessionID/
messageID before validation (P1: SDK parts lack these fields)
- Treat unknown part types as having content in
recover-empty-content-message-sdk.ts to prevent false placeholder
injection on image/file parts
- Replace local isRecord with shared import in parts-reader.ts
- P1: Use compacted timestamp check instead of nonexistent truncated
field in target-token-truncation.ts
- P1: Use defensive (response.data ?? response) pattern in
hook-message-injector/injector.ts to match codebase convention
- P2: Filter by tool type in countTruncatedResultsFromSDK to avoid
counting non-tool compacted parts
- P2: Treat thinking/meta-only messages as empty in both
empty-content-recovery-sdk.ts and message-builder.ts to align
SDK path with file-based logic
- Re-read messages from SDK after injectTextPartAsync to prevent stale
snapshot from causing duplicate placeholder injection (P2)
- Replace local isRecord with shared import from record-type-guard (P3)
- P2: treat unknown part types as non-content in message-builder messageHasContentFromSDK
- P3: reuse shared isRecord from record-type-guard.ts in opencode-http-api
Unknown part types should be treated as content (return true)
to match parity with the existing message-builder implementation.
Using continue would incorrectly mark messages with unknown part
types as empty, triggering false recovery.
- isTodo: allow optional id to match Todo interface, preventing
todos without ids from being silently dropped
- messageHasContentFromSDK: treat unknown part types as empty
(continue) instead of content (return true) for parity with
existing storage logic
- readMessagesFromSDK in recover-empty-content-message-sdk: wrap
SDK call in try/catch to prevent recovery from throwing
The previous commit incorrectly removed this function and its test
as dead code. While the local implementations in other files have
different return types (MessageData[], MessagePart[]) and cannot be
replaced by this shared version, the function is a valid tested
utility. Deleting tests is an anti-pattern in this project.
- Encode path segments with encodeURIComponent in HTTP API URLs
to prevent broken requests when IDs contain special characters
- Remove unused readMessagesFromSDK from messages-reader.ts
(production callers use local implementations; dead code)
- target-token-truncation: eliminate redundant SDK messages fetch by
extracting tool results from already-fetched toolPartsByKey map
- recover-thinking-block-order: wrap SDK message fetches in try/catch
so recovery continues gracefully on API errors
- thinking-strip: guard against missing part.id before calling
deletePart to prevent invalid HTTP requests
- executeDeduplication: now async, reads messages from SDK on SQLite via
client.session.messages() instead of JSON file reads
- truncateToolOutputsByCallId: now async, uses truncateToolResultAsync()
HTTP PATCH on SQLite instead of file-based truncateToolResult()
- deduplication-recovery: passes client through to both functions
- recovery-hook: passes ctx.client to attemptDeduplicationRecovery
Removes the last intentional feature gap on SQLite backend — dynamic
context pruning (dedup + tool-output truncation) now works on both
JSON and SQLite storage backends.
On SQLite backend, readParts() returns [] since JSON files don't exist.
Add isSqliteBackend() branch that reads parts from SDK via
client.session.messages() when failedAssistantMsg.parts is empty.