feat(sync): unify Google auth under :Pending auth (#72)

* feat(sync): unify Google auth under :Pending auth

Problem: users had to run `:Pending gtasks auth` and `:Pending gcal
auth` separately, producing two token files and two browser consents
for the same Google account.

Solution: introduce `oauth.google_client` with combined tasks +
calendar scopes and a single `google_tokens.json`. Remove per-backend
`auth`/`setup` from `gcal` and `gtasks`; add top-level `:Pending auth`
that prompts with `vim.ui.select` and delegates to the shared client's
`setup()` or `auth()` based on credential availability.

* docs: update vimdoc for unified Google auth

Problem: `doc/pending.txt` still documented per-backend `:Pending gtasks
auth` / `:Pending gcal auth` commands and separate token files, which no
longer exist after the auth unification.

Solution: add `:Pending auth` entry to COMMANDS and a new
`*pending-google-auth*` section covering the shared PKCE flow, combined
scopes, and `google_tokens.json`. Remove `auth` from gcal/gtasks action
tables and update all cross-references to use `:Pending auth`.

* ci: format
This commit is contained in:
Barrett Ruth 2026-03-05 21:08:22 -05:00
parent 34b8e1798a
commit 1dd40c9a9f
7 changed files with 102 additions and 77 deletions

View file

@ -828,6 +828,24 @@ function M.edit(id_str, rest)
log.info('Task #' .. id .. ' updated: ' .. table.concat(feedback, ', '))
end
---@return nil
function M.auth()
local oauth = require('pending.sync.oauth')
vim.ui.select({ 'gtasks', 'gcal', 'both' }, {
prompt = 'Authenticate:',
}, function(choice)
if not choice then
return
end
local creds = oauth.google_client:resolve_credentials()
if creds.client_id == oauth.BUNDLED_CLIENT_ID then
oauth.google_client:setup()
else
oauth.google_client:auth()
end
end)
end
---@param args string
---@return nil
function M.command(args)
@ -841,6 +859,8 @@ function M.command(args)
elseif cmd == 'edit' then
local id_str, edit_rest = rest:match('^(%S+)%s*(.*)')
M.edit(id_str, edit_rest)
elseif cmd == 'auth' then
M.auth()
elseif SYNC_BACKEND_SET[cmd] then
local action = rest:match('^(%S+)')
run_sync(cmd, action)