feat(calendar): add --with-zoom / --regenerate-zoom / --remove-zoom#590
Open
mvanhorn wants to merge 1 commit into
Open
feat(calendar): add --with-zoom / --regenerate-zoom / --remove-zoom#590mvanhorn wants to merge 1 commit into
mvanhorn wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gog calendarcan now create, regenerate, and remove Zoom video conferences as a first-party flag family, parallel to the existing--with-meetsurface. Addsgog zoom auth setupandgog zoom auth doctorfor Zoom Server-to-Server OAuth credential storage. Closes #589.Why this matters
The Zoom for Google Workspace add-on is UI-only. Calendar API's
conferenceData.createRequestdoes not reliably trigger third-party add-ons. The "agent schedules a Zoom meeting and attaches it to a Google Calendar event" niche is uncovered upstream:agent-plex/openclaw-zoomcovers Team Chat (different product),AIGC-Hackers/openclaw-zoom-agentjoins existing meetings (does not create or schedule).Architectural premise validated empirically before implementation. The reporter's research showed that
conferenceSolution.key.type = "addOn"is the generic legacy string (not Zoom-specific) and that the Zoom-for-Calendar add-on populatesconferenceData.entryPoints+conferenceSolution.{key,name,iconUri}. The open question was whether Google's Calendar API accepts these fields from a non-add-on OAuth client. I tested it: created a Calendar event withconferenceSolution.key.type = "addOn"+name = "Zoom Meeting"+ a Zoom-shaped entryPoint via a vanilla OAuth client; Google preserved all fields on read-back. The direct-write architecture works; noparameters.addOnParametersshim is required for API acceptance. UI parity (whether the Calendar UI renders Zoom branding vs a generic conference card) is the remaining unknown - see "Known caveat" below.Demo
Simulated demo (the implementer does not have a Zoom Pro account in the loop, so this is hand-crafted terminal animation, not a live capture). Live capture against the real
gogbinary post-gog zoom auth setupis a 2-minute exercise for anyone with a Zoom Pro account.Changes
internal/zoom/package: minimum-viable Zoom Meetings client (S2S OAuth token exchange + cached refresh, POST/users/{userId}/meetings, DELETE/meetings/{meetingId}). Production transport ishttp.DefaultTransport; tests inject ahttp.RoundTripper. NoInsecureSkipVerify.gog zoom auth setup/gog zoom auth doctorsubcommands. User-level OAuth scopes only (meeting:write,meeting:read,user:read). Admin scopes are explicitly deferred; agent-fleet--zoom-hostdelegation can land in a follow-up that gates*:adminbehind an explicit--adminflag.internal/secretswith namespaced keys (zoom-account/<alias>/client-secret,zoom-account/<alias>/access-token). Non-secret account metadata lives at~/.config/gogcli/zoom/<alias>.json(dir 0700, file 0600). No second keyring.buildConferenceDatarewritten to take aconferenceChoicestruct. Meet path is unchanged; Zoom path writes the addOn-shaped conferenceData after creating the Zoom meeting via the Zoom API.--with-zoomon an event that already has a Meet conference returnsusage("event already has a Meet conference; use --remove-meet first, then --with-zoom"). (--remove-meetitself is out of scope for this PR; see "Deferred" below.)--regenerate-zoom: cancel old meeting → on 404/410 proceed; on other error abort, Calendar event unchanged. Create new meeting → patch Calendar. If the Calendar patch fails, the newly-created Zoom meeting is cancelled.--remove-zoomcancels the Zoom meeting (404/410 = success, other error = stderr warning + proceed) then clears the Calendar conferenceData.redactZoomURLininternal/zoom/redact.gomasks thepwd=query parameter on every join URL reaching stdout/stderr.--include-passwordsflag (orGOG_ZOOM_INCLUDE_PASSWORDS=1) opts out for debugging.[zoom] meeting=<id> action=<cancel|delete|regenerate> ts=<rfc3339> cmd=<argv0>.make fmt,make lint,make build,make test,make docs-check,make ciall pass locally on ubuntu/macos (windows untested locally; CI will exercise it).Testing
internal/cmd/calendar_create_update_test.go:TestCalendarCreateCmd_WithZoomAndAttachments,TestCalendarUpdateCmd_WithZoom, idempotency variants,TestCalendarUpdateCmd_RegenerateZoomReplacesConference,TestCalendarUpdateCmd_RemoveZoom.TestCalendarUpdateCmd_WithZoomOnExistingMeetEventRejects,TestCalendarUpdateCmd_WithZoomNoCredentialsErrors,TestCalendarUpdateCmd_RegenerateZoomWithUnparseablePriorMeetingWarns.internal/zoom/client_test.goexercises token-refresh, 404/410-treated-as-success on delete, and 5xx error-path viahttptest.key.type="addOn"+name/iconUri/entryPointson round-trip from a non-add-on OAuth client.Known caveat
Calendar UI Zoom branding parity was not visually verified during Phase 0. The API accepts and stores the addOn-shaped conferenceData; whether Google renders the Zoom card vs a generic conference card depends on whether the Calendar UI gates on
parameters.addOnParameters.parameters(add-on-internal Apps Script state). If maintainer testing reveals the UI shows a generic card, a follow-up can populate plausibleaddOnParametersvalues - the empirical fallback path noted in #589's Open Question 3.Deferred to follow-up PRs
To keep this PR close to the project's median size and easy to review:
gog zoom meeting create|get|list|update|deletesubtree (the issue's Tier 2 "nice-to-have, could be follow-up PR").--remove-meet(real gap, but adjacent to this work; separate minimal PR keeps the diff focused).--zoom-no-notesand--zoom-host <email>flags (latter needs the*:adminscope split).gog zoom auth tokenssubcommand.Open Questions answered in #589
Flag naming: chose the concrete
--with-zoomfamily over a generic--conference-provider zoomform. Rationale: discoverability + mirrors the existing--with-meetprecedent. A generic abstraction is more durable if a second non-Meet provider lands; happy to refactor at review time if you prefer that direction.Implementation architecture: direct Zoom API write (path a in the issue), empirically validated. Calendar
createRequestpassthrough (path b) was rejected because it depends on third-party add-ons implementing Google's Conference Add-oncreateConferencecallback - Zoom's add-on does not.addOnParametersserver-side validation: not required for API acceptance per Phase 0 test. UI rendering parity is the open follow-up question (see "Known caveat").Fixes #589