Commit 8619cfa
authored
* feat: single-run init wizard and gro me
Closes #107
Replaces the two-pass `gro init` flow with a huh-driven wizard that
ingests credentials.json from clipboard, terminal paste, or file path
in a single invocation. Adds a new `gro me` command modeled on
jtk me — a token-dense one-liner (resourceName | displayName |
primaryEmail) backed by the People API people/me endpoint, with
--id (primary email), --extended (scopes + token expiry +
storage backend), and --json shapes.
Wizard improvements:
- Detects existing credentials.json and short-circuits.
- --credentials-file path bypass for scripting.
- huh.NewConfirm before opening the consent URL; --no-browser opt-out.
- huh.NewInput with in-place validation for the redirect URL paste.
- Re-auth confirm via huh.NewConfirm when the stored token is expired.
- Cache TTL prompt now fires on first runs (snapshot config existence
before saving granted scopes — the existing code's ordering bug
made the prompt unreachable).
- Explicit os.Chmod(path, 0600) after WriteFile so credentials.json
can't keep loose perms when overwritten.
- Cloud Console instructions now list Gmail, Calendar, Drive, and
People APIs.
gro me:
- Pipe one-liner with `-` for empty fields and `\|` escaping.
- People API call site detects insufficient-scope 403s specifically
(insufficientPermissions / ACCESS_TOKEN_SCOPE_INSUFFICIENT) and
rewrites them to "Run 'gro init' to re-authenticate". Other 403s
(service-disabled, project-not-permitted) pass through unchanged.
- Token expiry read after the API call so PersistentTokenSource
refreshes are reflected.
- --id and --extended are mutually exclusive.
Adds:
- internal/people/ — focused client for people/me + insufficient-scope
error detection.
- internal/view/ — small Success/Error/Info/Printf/Println helper.
- Architecture-test registrations for the new packages.
* fix(init): close stale-scope remediation loop and stop lying about success
Addresses Codex PR review findings on #108:
- Stale-scope remediation loop (BLOCKER): a Gmail-valid but People-
insufficient token used to silently pass init's existing-token branch,
while gro me told users to "run gro init". Init now verifies People in
addition to Gmail when a token exists, runs auth.CheckScopesMigration
on the recorded scopes, and triggers re-auth on either failure mode.
Extracted tryExistingToken seam to keep runWith readable.
- --no-verify regression: existing token path is now selected first,
with API calls suppressed when --no-verify is set (rather than
forcing a fresh OAuth flow on every invocation).
- People-failure-is-fatal: post-OAuth People verify is no longer
swallowed as a warning followed by "Setup complete" — init's contract
is that gro me works when init returns nil.
- Output via Cobra writers / View.Out instead of bare os.Stdout/os.Stderr,
so output redirection works and tests can drive both streams.
- Removed unused initDeps.GetToken field and the io.Discard import sentinel.
New tests cover the stale-scope re-auth, --no-verify-skips-API, fatal
People failure, and (in me_test.go) real-config stale/missing/empty
scope cases via XDG_CONFIG_HOME.
* fix(init): plumb verified profile through finishExisting; don't claim scopes for existing tokens
Addresses second-pass Codex PR review:
- Existing-token verify only calls People once now: tryExistingToken
passes the verified Profile into finishExisting, which renders the
one-liner from that result instead of re-fetching.
- finishExisting no longer writes GrantedScopes for existing tokens.
We don't actually know which scopes the token has — only a fresh
OAuth flow does. The pre-fix code was claiming auth.AllScopes for
any existing-token-without-config-file run, which would defeat the
same stale-scope detection later.
- New TestRunWithRecordedStaleScopesReauths covers the loud-and-early
CheckScopesMigration branch (asserts DeleteToken happens before any
Gmail/People call on the stale token).
* test: cover gaps surfaced by TDD assessment on PR #108
Adds tests for the five gaps the TDD review flagged:
- ensureCredentials file-path wizard branch (credChoice="file" was the
only cred-source path without coverage).
- ensureCredentials short-circuits when credentials.json already exists
and never invokes the wizard's first prompt.
- ConfirmOpenBrowser=true causes OpenBrowser to actually fire (the
existing wizard tests all said "no" to the open-browser prompt, so
the real branch was never exercised).
- Recorded-stale-scope re-auth path now also asserts the TTL prompt
fires after the fresh OAuth flow.
- run() end-to-end with --extended + --json (regression guard for
gatherExtras being skipped when jsonOutput is true).
* fix: address daemon Should-Fix findings on PR #108
- tryExistingToken: run CheckScopesMigration BEFORE the --no-verify
branch so a stale-scoped token + --no-verify doesn't reopen the same
remediation loop the wizard exists to close. Added a "Token accepted"
line on the --no-verify path so users don't see a silent return.
- gro me: SilenceErrors+SilenceUsage so errReauth's actionable message
isn't shadowed by cobra's "Error: re-authentication required" prefix.
- RenderJSON --id: normalize empty PrimaryEmail to "-" so JSON and text
paths agree on empty-field representation.
- grantedScopes(): return nil instead of falsely claiming auth.AllScopes
when no scope record exists. Old behavior overstated what the token
was actually granted under --extended.
- README: clarify that init prints the gro me one-liner automatically;
the "run gro me" line was contradicting that.
* docs: show -j short form for gro me --json
* docs(init): clarify retry-loop scope per daemon review
* fix: address daemon Should-Fix findings (round 2)
- gatherExtras: add `tok != nil` guard so a nil token from keychain
doesn't panic on tok.Expiry.IsZero().
- RenderJSON: revert the --id normalization so all three JSON shapes
(default, --id, --extended) consistently emit raw values. Text
rendering still uses "-" via normalizeField; JSON keeps empty
strings, which is the more machine-friendly convention.
- huh.NewText paste prompt: "Press Esc when done" was misleading
(Esc cancels in huh). Updated to "Press Tab when done".
- Verify cobra SilenceErrors actually suppresses the "Error: ..."
prefix end-to-end via TestNewCommandSilencesCobraErrorOnReauth.
- TestRunWithExistingTokenNoVerifyStillCatchesStaleScopes: new test
asserting --no-verify does NOT bypass the recorded-scope check.
- README: document the cache-TTL prompt as wizard step 4.
* fix: route 'Warning:' messages to stderr in init wizard
Daemon round 3 noted that View.Info writes to stdout, but the three
'Warning: saving ...' callers were misuse — they should be on stderr so
scripts redirecting stdout don't capture them. Switching to View.Error
matches the existing semantics rather than redefining Info.
1 parent 15db54d commit 8619cfa
15 files changed
Lines changed: 2528 additions & 367 deletions
File tree
- docs
- internal
- architecture
- cmd
- initcmd
- me
- root
- people
- view
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
138 | 139 | | |
139 | 140 | | |
140 | 141 | | |
141 | | - | |
| 142 | + | |
142 | 143 | | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
| 144 | + | |
156 | 145 | | |
157 | 146 | | |
158 | 147 | | |
159 | 148 | | |
160 | 149 | | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
167 | 162 | | |
168 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
169 | 176 | | |
170 | 177 | | |
171 | 178 | | |
| |||
175 | 182 | | |
176 | 183 | | |
177 | 184 | | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
178 | 198 | | |
179 | 199 | | |
180 | 200 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| 34 | + | |
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
| |||
38 | 41 | | |
39 | 42 | | |
40 | 43 | | |
41 | | - | |
| 44 | + | |
42 | 45 | | |
43 | 46 | | |
44 | 47 | | |
| |||
48 | 51 | | |
49 | 52 | | |
50 | 53 | | |
51 | | - | |
| 54 | + | |
52 | 55 | | |
53 | 56 | | |
54 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
6 | 10 | | |
7 | 11 | | |
8 | 12 | | |
| |||
12 | 16 | | |
13 | 17 | | |
14 | 18 | | |
| 19 | + | |
| 20 | + | |
15 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
16 | 31 | | |
17 | 32 | | |
18 | 33 | | |
| |||
21 | 36 | | |
22 | 37 | | |
23 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
24 | 48 | | |
| 49 | + | |
25 | 50 | | |
26 | 51 | | |
27 | 52 | | |
28 | 53 | | |
29 | 54 | | |
30 | 55 | | |
31 | 56 | | |
| 57 | + | |
32 | 58 | | |
33 | 59 | | |
34 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
7 | 17 | | |
8 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
9 | 47 | | |
| 48 | + | |
| 49 | + | |
10 | 50 | | |
11 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
12 | 56 | | |
13 | 57 | | |
14 | 58 | | |
| |||
30 | 74 | | |
31 | 75 | | |
32 | 76 | | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
33 | 95 | | |
34 | 96 | | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
35 | 100 | | |
36 | 101 | | |
37 | 102 | | |
38 | 103 | | |
39 | 104 | | |
40 | 105 | | |
41 | 106 | | |
| 107 | + | |
| 108 | + | |
42 | 109 | | |
43 | 110 | | |
44 | 111 | | |
| |||
55 | 122 | | |
56 | 123 | | |
57 | 124 | | |
| 125 | + | |
| 126 | + | |
58 | 127 | | |
59 | 128 | | |
60 | 129 | | |
61 | 130 | | |
62 | 131 | | |
63 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
64 | 136 | | |
65 | 137 | | |
66 | 138 | | |
| |||
0 commit comments