acuvo-code 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -149,3 +149,60 @@ export function openBrowser(url, { platform = process.platform, spawn } = {}) {
149
149
  return false;
150
150
  }
151
151
  }
152
+
153
+ /**
154
+ * ── ⭐⭐⭐ ONE LOGIN FLOW, TWO DOORS ─────────────────────────────────────────
155
+ *
156
+ * Drives the whole grant: ask for a code, show it, open a browser, wait, save.
157
+ * Reached from `acuvo --login` AND from a bare `acuvo` that finds no
158
+ * credential — the second of which is what makes typing `acuvo` enough, the
159
+ * way typing `claude` is.
160
+ *
161
+ * ⚠️ IT LIVES HERE, NOT IN `bin/`. The first version was written inline inside
162
+ * the `--login` branch and was needed by a second caller within the hour. A fix
163
+ * that lives inside one caller is a fix for one caller — this codebase has paid
164
+ * for that three times today alone. Extracted before the second copy existed
165
+ * rather than after.
166
+ *
167
+ * ⚠️ IT THROWS RATHER THAN EXITING. `bin/` owns exit codes and phrasing; a
168
+ * library that calls `process.exit` cannot be tested and cannot be reused.
169
+ *
170
+ * @returns {Promise<{token: string, restricted: boolean|null, userCode: string}>}
171
+ */
172
+ export async function runDeviceLogin({
173
+ gatewayUrl,
174
+ write = (s) => process.stderr.write(s),
175
+ spawn,
176
+ requestCode = requestDeviceCode,
177
+ poll = pollForKey,
178
+ open = openBrowser,
179
+ saveAccount,
180
+ } = {}) {
181
+ const start = await requestCode(gatewayUrl);
182
+ const url = start.verification_uri_complete || start.verification_uri;
183
+
184
+ /**
185
+ * ⚠️ THE URL AND CODE ARE PRINTED WHETHER OR NOT THE BROWSER OPENS. This runs
186
+ * over SSH, in containers, and in terminals with no desktop session, where
187
+ * opening a browser is impossible by definition — a flow that assumes the
188
+ * open worked strands every remote user.
189
+ */
190
+ write(`\nYour code: ${start.user_code}\n\n`);
191
+ const opened = open(url, { spawn });
192
+ write(opened
193
+ ? `Opened your browser to approve it. If nothing appeared:\n ${url}\n\n`
194
+ : `Open this to approve it:\n ${url}\n\n`);
195
+ write('Waiting for approval… (Ctrl-C to cancel)\n');
196
+
197
+ const granted = await poll(gatewayUrl, start.device_code, {
198
+ intervalMs: (start.interval ?? 2) * 1000,
199
+ expiresInMs: (start.expires_in ?? 600) * 1000,
200
+ });
201
+
202
+ const saved = saveAccount ? saveAccount(granted.api_key) : null;
203
+ return {
204
+ token: granted.api_key,
205
+ restricted: saved && typeof saved.restricted === 'boolean' ? saved.restricted : null,
206
+ userCode: start.user_code,
207
+ };
208
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acuvo-code",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Acuvo Code — the terminal client for the Acuvo capability registry. Zero dependencies, by design.",
5
5
  "type": "module",
6
6
  "bin": {