mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-30 16:20:35 +02:00
* feat(github): GitHub App backend for PR ↔ issue linking - New tables: github_installation (workspace ↔ App install), github_pull_request (mirrored PR state), issue_pull_request (M:N link). - Webhook handler verifies HMAC-SHA256, upserts PR rows, parses issue identifiers from PR title/body/branch and auto-links them. Merging a linked PR moves the issue to done. - Connect/setup endpoints power the zero-config "Connect GitHub" install flow; state token is HMAC-signed so the setup callback can recover the workspace. - Workspace-scoped admin routes for listing/disconnecting installations, plus a per-issue `pull-requests` list endpoint. Co-authored-by: multica-agent <github@multica.ai> * feat(github): UI for connecting GitHub and viewing linked PRs - Settings → Integrations: new tab with Connect GitHub / installations list / disconnect, gated on the deployment having the App configured. - Issue detail sidebar: Pull requests section showing linked PR title, repo, state (open/draft/merged/closed), and author, with deep link to GitHub. - Real-time refresh: github_installation:* and pull_request:* events invalidate the matching TanStack Query caches. Co-authored-by: multica-agent <github@multica.ai> * fix(github): address review — null actor, role gating, configured guard, scoped uninstall broadcast - listeners: use optionalUUID(e.ActorID) so the system actor on the github-driven issue:updated event no longer panics activity / notification listeners; merged-PR → issue done now produces a status_changed activity and inbox entry. - IntegrationsTab: gate the admin-only installations query on canManage so members no longer hit /github/installations 403; the configured/not-configured copy is also scoped to admins. - backend: introduce isGitHubConfigured() requiring both GITHUB_APP_SLUG and GITHUB_WEBHOOK_SECRET, and surface that single flag from list-installations + connect endpoints so the frontend Connect button stays disabled until both are set. - DeleteGitHubInstallationByInstallationID now RETURNs workspace_id; webhook handler publishes github_installation:deleted scoped to the right workspace so already-open Settings tabs invalidate in real time. ErrNoRows on a re-fired delete short-circuits cleanly. - tests: focused webhook integration coverage (auto-link + merge → done, cancelled preservation, uninstall returns workspace). Co-authored-by: multica-agent <github@multica.ai> * fix(github): i18n the new GitHub UI strings to satisfy lint CI flagged every literal string in the Integrations tab, the Pull requests sidebar section, and the per-PR row label. Move them through useT() and add the matching `integrations.*` block to settings.json (en / zh-Hans) plus `detail.section_pull_requests` / `detail.pull_request_state_*` / loading + empty copy under `issues.json`. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai>
118 lines
4.1 KiB
Go
118 lines
4.1 KiB
Go
package protocol
|
|
|
|
// Event types for WebSocket communication between server, web clients, and daemon.
|
|
const (
|
|
// Issue events
|
|
EventIssueCreated = "issue:created"
|
|
EventIssueUpdated = "issue:updated"
|
|
EventIssueDeleted = "issue:deleted"
|
|
|
|
// Comment events
|
|
EventCommentCreated = "comment:created"
|
|
EventCommentUpdated = "comment:updated"
|
|
EventCommentDeleted = "comment:deleted"
|
|
EventCommentResolved = "comment:resolved"
|
|
EventCommentUnresolved = "comment:unresolved"
|
|
EventReactionAdded = "reaction:added"
|
|
EventReactionRemoved = "reaction:removed"
|
|
EventIssueReactionAdded = "issue_reaction:added"
|
|
EventIssueReactionRemoved = "issue_reaction:removed"
|
|
|
|
// Agent events
|
|
EventAgentStatus = "agent:status"
|
|
EventAgentCreated = "agent:created"
|
|
EventAgentArchived = "agent:archived"
|
|
EventAgentRestored = "agent:restored"
|
|
|
|
// Task events (server <-> daemon).
|
|
// Each event maps to a status transition on agent_task_queue. Front-end
|
|
// subscribes by `task:` prefix and invalidates the workspace task
|
|
// snapshot, so the granularity here is "what does the user want to see
|
|
// change" — not "every internal status flip".
|
|
EventTaskQueued = "task:queued" // ∅ → queued (enqueue / retry create)
|
|
EventTaskDispatch = "task:dispatch" // queued → dispatched (daemon claim)
|
|
EventTaskProgress = "task:progress"
|
|
EventTaskCompleted = "task:completed" // running → completed
|
|
EventTaskFailed = "task:failed" // running → failed
|
|
EventTaskMessage = "task:message"
|
|
EventTaskCancelled = "task:cancelled" // * → cancelled
|
|
|
|
// Inbox events
|
|
EventInboxNew = "inbox:new"
|
|
EventInboxRead = "inbox:read"
|
|
EventInboxArchived = "inbox:archived"
|
|
EventInboxBatchRead = "inbox:batch-read"
|
|
EventInboxBatchArchived = "inbox:batch-archived"
|
|
|
|
// Workspace events
|
|
EventWorkspaceUpdated = "workspace:updated"
|
|
EventWorkspaceDeleted = "workspace:deleted"
|
|
|
|
// Member events
|
|
EventMemberAdded = "member:added"
|
|
EventMemberUpdated = "member:updated"
|
|
EventMemberRemoved = "member:removed"
|
|
|
|
// Subscriber events
|
|
EventSubscriberAdded = "subscriber:added"
|
|
EventSubscriberRemoved = "subscriber:removed"
|
|
|
|
// Activity events
|
|
EventActivityCreated = "activity:created"
|
|
|
|
// Skill events
|
|
EventSkillCreated = "skill:created"
|
|
EventSkillUpdated = "skill:updated"
|
|
EventSkillDeleted = "skill:deleted"
|
|
|
|
// Chat events
|
|
EventChatMessage = "chat:message"
|
|
EventChatDone = "chat:done"
|
|
EventChatSessionRead = "chat:session_read"
|
|
EventChatSessionDeleted = "chat:session_deleted"
|
|
|
|
// Project events
|
|
EventProjectCreated = "project:created"
|
|
EventProjectUpdated = "project:updated"
|
|
EventProjectDeleted = "project:deleted"
|
|
EventProjectResourceCreated = "project_resource:created"
|
|
EventProjectResourceDeleted = "project_resource:deleted"
|
|
|
|
// Label events
|
|
EventLabelCreated = "label:created"
|
|
EventLabelUpdated = "label:updated"
|
|
EventLabelDeleted = "label:deleted"
|
|
EventIssueLabelsChanged = "issue_labels:changed"
|
|
|
|
// Pin events
|
|
EventPinCreated = "pin:created"
|
|
EventPinDeleted = "pin:deleted"
|
|
EventPinReordered = "pin:reordered"
|
|
|
|
// Invitation events
|
|
EventInvitationCreated = "invitation:created"
|
|
EventInvitationAccepted = "invitation:accepted"
|
|
EventInvitationDeclined = "invitation:declined"
|
|
EventInvitationRevoked = "invitation:revoked"
|
|
|
|
// Autopilot events
|
|
EventAutopilotCreated = "autopilot:created"
|
|
EventAutopilotUpdated = "autopilot:updated"
|
|
EventAutopilotDeleted = "autopilot:deleted"
|
|
EventAutopilotRunStart = "autopilot:run_start"
|
|
EventAutopilotRunDone = "autopilot:run_done"
|
|
|
|
// Daemon events
|
|
EventDaemonHeartbeat = "daemon:heartbeat"
|
|
EventDaemonHeartbeatAck = "daemon:heartbeat_ack"
|
|
EventDaemonRegister = "daemon:register"
|
|
EventDaemonTaskAvailable = "daemon:task_available"
|
|
|
|
// GitHub integration events
|
|
EventGitHubInstallationCreated = "github_installation:created"
|
|
EventGitHubInstallationDeleted = "github_installation:deleted"
|
|
EventPullRequestLinked = "pull_request:linked"
|
|
EventPullRequestUpdated = "pull_request:updated"
|
|
EventPullRequestUnlinked = "pull_request:unlinked"
|
|
)
|