Conversation
- Add new 'happy opencode' subcommand for OpenCode AI terminal control - Implement OpenCodeClient with HTTP/SSE API support (port 4096) - Add message format conversion between Happy and OpenCode - Implement permission handling with mobile app integration - Support model/provider selection and permission modes (--yolo, --accept-edits) OpenCode provides a native HTTP API unlike Claude/Codex PTY spawning, enabling cleaner integration with real-time SSE event streaming.
|
@D36u99er is this PR still being pursued? :) |
| }; | ||
| } | ||
|
|
||
| export type OpenCodePermissionReply = |
There was a problem hiding this comment.
// PR uses:
type OpenCodePermissionReply = 'allow' | 'allowSession' | 'allowForever' | 'deny' | 'denySession' | 'denyForever';
// OpenCode actually uses:
type PermissionReply = 'once' | 'always' | 'reject';
Impact: All permission responses will fail. The API expects once/always/reject, but the code sends allow/allowSession/etc.
Fix Required: Update OpenCodePermissionReply to 'once' | 'always' | 'reject' and update all usages.
https://github.com/anomalyco/opencode/blob/aa17729008cfeb94c550c0b1b0f14aeae54a372a/packages/web/src/content/docs/permissions.mdx#L141
| this.emit('message:part', payload.properties as unknown as OpenCodeMessagePart); | ||
| break; | ||
|
|
||
| case 'permission.created': |
There was a problem hiding this comment.
case 'permission.created': // Wrong
this.emit('permission:request', ...);
OpenCode emits permission.asked, not permission.created. Permission requests will never be received.
Fix: Change to case 'permission.asked':.
There was a problem hiding this comment.
Missing session.error Event Handling (openCodeClient.ts)
The SSE handler doesn't handle session.error events. When OpenCode encounters an error (API error, message aborted, output length exceeded), the client will silently ignore it.
Impact: Errors go unreported to the mobile client.
There was a problem hiding this comment.
Missing Signal Handlers (runOpenCode.ts)
Unlike runClaude.ts (lines 362-375), runOpenCode.ts lacks:
- SIGTERM/SIGINT handlers
- uncaughtException handler
- unhandledRejection handler
Risk: Orphaned sessions when process is killed, no cleanup performed.
| parts: OpenCodeMessagePart[]; | ||
| } | ||
|
|
||
| export interface OpenCodePermissionRequest { |
There was a problem hiding this comment.
Permission Request Structure Mismatch
OpenCode's PermissionRequest has different fields than defined:
// PR defines:
interface OpenCodePermissionRequest {
id: string;
sessionID: string;
messageID: string; // Not in OpenCode
partID: string; // Not in OpenCode
metadata: { ... }; // Different structure
}
// OpenCode actually has:
interface PermissionRequest {
id: string;
sessionID: string;
permission: string; // e.g., "read", "bash", "edit"
patterns: string[]; // Patterns being requested
metadata: { ... };
always: string[]; // Patterns to approve if "always"
tool?: { messageID, callID };
}
There was a problem hiding this comment.
Missing Message Part Types, OpenCode has more message part types not handled:
- CompactionPart - for context compaction
- SubtaskPart - for agent subtasks
- RetryPart - for retry information
- StepFinishPart - for step completion
| ); | ||
| } | ||
|
|
||
| private getPermissionKey(request: OpenCodePermissionRequest): string { |
There was a problem hiding this comment.
Using JSON.stringify for key generation is fragile (object property order). Use a deterministic hash like hashObject from existing utils.
There was a problem hiding this comment.
OpenCode supports HTTP basic auth via OPENCODE_SERVER_PASSWORD environment variable. The client doesn't include auth headers.
| export class OpenCodeClient extends EventEmitter { | ||
| private baseUrl: string; | ||
| private timeout: number; | ||
| private eventSource: EventSource | null = null; |
There was a problem hiding this comment.
Unused eventSource Property, the code uses fetch-based SSE, but declares an unused EventSource property.
| const sessions = await this.listSessions(); | ||
| const dir = directory || process.cwd(); | ||
|
|
||
| const existing = sessions.find(s => s.directory === dir); |
There was a problem hiding this comment.
This exact match may fail with trailing slashes or symlinks. Consider normalizing paths.
Summary
This PR adds support for OpenCode (https://github.com/anomalyco/opencode) as a new agent flavor, enabling mobile control of OpenCode AI terminals through the Happy app.
Key Changes
happy opencodesubcommand - Start OpenCode sessions with mobile control--modeland--providerflags for model configurationFiles Added
Usage
Why OpenCode?
OpenCode provides:
Related
Testing