-
Notifications
You must be signed in to change notification settings - Fork 238
feat: add OpenCode integration support #116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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