@runalabs/rill-cli 0.1.16 → 0.1.17
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.
- package/README.md +2 -0
- package/dist/cli.js +29 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -370,6 +370,8 @@ Progress runs through `uploading` → `queued` → `encoding` → `processing`
|
|
|
370
370
|
|
|
371
371
|
Run `rill connect --email you@example.com` to authorize account access or keep your anonymous recordings. Open the displayed link, sign in, and enter the code yourself. Approval allows creation and reading of your existing and new recordings for 90 days, with automatic renewal of one-hour access tokens. Revoke the connection in Settings → Agent access to stop access and renewal. Deletion and changes to existing sharing settings are not included.
|
|
372
372
|
|
|
373
|
+
Browser approval does not finish the handshake: the CLI must collect and save credentials. With `--no-wait`, keep polling the returned `connect status <authorizationId>` command until `authenticated`. Starting with 0.1.17, the CLI checks the server even after its local approval deadline. Approval codes expire after ten minutes; successful approval starts a separate 30-minute collection window, with a 60-second lost-response retry window after first collection. If collection expires, run `connect --email` again with the same account to request fresh human approval while preserving the registration and recordings. Do not delete saved credentials to recover. Auth requests include the CLI version for consent-aware diagnostics.
|
|
374
|
+
|
|
373
375
|
Use `rill record list` to list accessible recordings and `rill inspect <recording-id>` for private recording details. `rill inspect <share-url>` continues to work without account access. The existing `rill login` and `RILL_TOKEN` flows remain supported. Local credential storage requires macOS Keychain, Linux Secret Service, or Windows current-user DPAPI.
|
|
374
376
|
|
|
375
377
|
### Check the connected account
|
package/dist/cli.js
CHANGED
|
@@ -127,6 +127,11 @@ function browserAttachment(cdpUrl, tabId) {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// src/version.ts
|
|
131
|
+
import { createRequire } from "module";
|
|
132
|
+
var packageJson = createRequire(import.meta.url)("../package.json");
|
|
133
|
+
var CLI_VERSION = packageJson.version;
|
|
134
|
+
|
|
130
135
|
// src/agent-session.ts
|
|
131
136
|
var JWT_GRANT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
|
132
137
|
var CLAIM_GRANT = "urn:workos:agent-auth:grant-type:claim";
|
|
@@ -150,7 +155,7 @@ async function request(apiUrl, path, body, form = false) {
|
|
|
150
155
|
method: "POST",
|
|
151
156
|
redirect: "error",
|
|
152
157
|
signal: AbortSignal.timeout(15e3),
|
|
153
|
-
headers: { "Content-Type": form ? "application/x-www-form-urlencoded" : "application/json" },
|
|
158
|
+
headers: { "Content-Type": form ? "application/x-www-form-urlencoded" : "application/json", "X-Rill-CLI-Version": CLI_VERSION },
|
|
154
159
|
body: form ? new URLSearchParams(Object.entries(body).map(([key2, value2]) => [key2, String(value2)])) : JSON.stringify(body)
|
|
155
160
|
});
|
|
156
161
|
const value = await response.json();
|
|
@@ -246,6 +251,12 @@ async function connectAgent(apiUrl, email3, options = {}) {
|
|
|
246
251
|
async function beginConnection(apiUrl, email3) {
|
|
247
252
|
if (process.env.RILL_TOKEN) throw new Error("Unset RILL_TOKEN before connecting a local identity.");
|
|
248
253
|
let saved = parseAuthorization(await loadStoredCredential(apiUrl));
|
|
254
|
+
if (saved?.connection?.status === "pending" && saved.connection.expiresAt <= Date.now()) {
|
|
255
|
+
if (saved.connection.email !== email3) throw new Error("Use the original account to finish or recover this connection.");
|
|
256
|
+
const result = await pollSavedConnection(apiUrl, saved.connection.id);
|
|
257
|
+
if (result.status !== "expired") return result;
|
|
258
|
+
saved = parseAuthorization(await loadStoredCredential(apiUrl));
|
|
259
|
+
}
|
|
249
260
|
if (saved?.connection?.status === "pending" && saved.connection.expiresAt > Date.now()) {
|
|
250
261
|
if (saved.connection.email !== email3) throw new Error("A connection for another email is pending. Let it expire before starting a different connection.");
|
|
251
262
|
process.stderr.write(`Open ${saved.connection.verificationUri}
|
|
@@ -259,6 +270,22 @@ Sign in as ${email3} and enter ${saved.connection.userCode}. Approve only the re
|
|
|
259
270
|
const result = await request(apiUrl, "/agent/identity/claim", { claim_token: saved.claimToken, email: email3 });
|
|
260
271
|
claim = result.claim_attempt;
|
|
261
272
|
} catch (error51) {
|
|
273
|
+
if (error51 instanceof AgentAuthError && error51.code === "claim_already_approved") {
|
|
274
|
+
saved.connection ??= {
|
|
275
|
+
id: randomBytes(16).toString("hex"),
|
|
276
|
+
email: email3,
|
|
277
|
+
verificationUri: "",
|
|
278
|
+
userCode: "",
|
|
279
|
+
expiresAt: Date.now(),
|
|
280
|
+
interval: 5,
|
|
281
|
+
nextPollAt: 0,
|
|
282
|
+
status: "pending"
|
|
283
|
+
};
|
|
284
|
+
saved.connection.status = "pending";
|
|
285
|
+
saved.connection.nextPollAt = 0;
|
|
286
|
+
await save(apiUrl, saved);
|
|
287
|
+
return pollSavedConnection(apiUrl, saved.connection.id);
|
|
288
|
+
}
|
|
262
289
|
if (!(error51 instanceof AgentAuthError) || error51.code !== "claim_expired") throw error51;
|
|
263
290
|
}
|
|
264
291
|
}
|
|
@@ -309,11 +336,6 @@ async function pollSavedConnection(apiUrl, authorizationId) {
|
|
|
309
336
|
if (!saved?.connection || saved.connection.id !== authorizationId) throw new AgentAuthError("authorization_not_found", "No matching saved connection for this API URL. Use the latest connect response.");
|
|
310
337
|
const connection = saved.connection;
|
|
311
338
|
if (connection.status !== "pending") return connectionView(apiUrl, saved);
|
|
312
|
-
if (Date.now() >= connection.expiresAt) {
|
|
313
|
-
connection.status = "expired";
|
|
314
|
-
await save(apiUrl, saved);
|
|
315
|
-
return connectionView(apiUrl, saved);
|
|
316
|
-
}
|
|
317
339
|
if (Date.now() < connection.nextPollAt) return connectionView(apiUrl, saved);
|
|
318
340
|
connection.nextPollAt = Date.now() + connection.interval * 1e3;
|
|
319
341
|
await save(apiUrl, saved);
|
|
@@ -322,7 +344,7 @@ async function pollSavedConnection(apiUrl, authorizationId) {
|
|
|
322
344
|
saved = withTokens({ version: 1, anonymous: false, connection: { ...connection, status: "authenticated", userCode: "" } }, tokens);
|
|
323
345
|
} catch (error51) {
|
|
324
346
|
if (!(error51 instanceof AgentAuthError)) throw error51;
|
|
325
|
-
if (error51.code === "expired_token" || error51.code === "claim_expired") connection.status = "expired";
|
|
347
|
+
if (error51.code === "expired_token" || error51.code === "claim_expired" || error51.code === "claim_delivery_expired" || error51.code === "claimed_or_in_flight" && Date.now() >= connection.expiresAt) connection.status = "expired";
|
|
326
348
|
else if (error51.code === "access_denied" || error51.code === "claim_revoked") connection.status = "denied";
|
|
327
349
|
else if (error51.code === "slow_down") {
|
|
328
350
|
connection.interval += 5;
|
|
@@ -16771,13 +16793,6 @@ async function withRunFeedback(session, start) {
|
|
|
16771
16793
|
|
|
16772
16794
|
// src/doctor.ts
|
|
16773
16795
|
import { spawn as spawn7 } from "child_process";
|
|
16774
|
-
|
|
16775
|
-
// src/version.ts
|
|
16776
|
-
import { createRequire } from "module";
|
|
16777
|
-
var packageJson = createRequire(import.meta.url)("../package.json");
|
|
16778
|
-
var CLI_VERSION = packageJson.version;
|
|
16779
|
-
|
|
16780
|
-
// src/doctor.ts
|
|
16781
16796
|
var defaultDependencies = {
|
|
16782
16797
|
platform: process.platform,
|
|
16783
16798
|
encoding: "remote",
|