free-pi-cli 0.6.8 → 0.6.9
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/dist/index.js +1 -1
- package/dist/{main-tyjwqhr5.js → main-cgxt6te1.js} +378 -92
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14382,7 +14382,8 @@ var GithubDeviceResponseSchema = exports_external.object({
|
|
|
14382
14382
|
user_code: exports_external.string(),
|
|
14383
14383
|
verification_uri: exports_external.string(),
|
|
14384
14384
|
interval: exports_external.number(),
|
|
14385
|
-
expires_in: exports_external.number().optional()
|
|
14385
|
+
expires_in: exports_external.number().optional(),
|
|
14386
|
+
verification_uri_complete: exports_external.string().optional()
|
|
14386
14387
|
});
|
|
14387
14388
|
var AuthTokenRequestSchema = exports_external.object({
|
|
14388
14389
|
session_id: exports_external.string().uuid()
|
|
@@ -14449,8 +14450,15 @@ var GuestUnavailableResponseSchema = exports_external.object({
|
|
|
14449
14450
|
message: exports_external.string(),
|
|
14450
14451
|
reason: exports_external.enum(["disabled", "global_budget", "ip_sessions", "ip_allowance"])
|
|
14451
14452
|
});
|
|
14453
|
+
var FunnelEventNameSchema = exports_external.enum([
|
|
14454
|
+
"device_code_shown",
|
|
14455
|
+
"browser_opened",
|
|
14456
|
+
"device_code_reminted",
|
|
14457
|
+
"device_code_expired",
|
|
14458
|
+
"device_poll_slow_down"
|
|
14459
|
+
]);
|
|
14452
14460
|
var FunnelEventRequestSchema = exports_external.object({
|
|
14453
|
-
event:
|
|
14461
|
+
event: FunnelEventNameSchema,
|
|
14454
14462
|
session_id: exports_external.string().uuid().optional()
|
|
14455
14463
|
});
|
|
14456
14464
|
var ReturnBonusTelemetrySchema = exports_external.object({
|
|
@@ -14629,6 +14637,11 @@ var ConfigSchema = exports_external.object({
|
|
|
14629
14637
|
maxOutputTokens: exports_external.number().int().min(1).default(32768),
|
|
14630
14638
|
accountsPerDayCeiling: exports_external.number().int().default(500),
|
|
14631
14639
|
authRatePerIpPerHour: exports_external.number().int().default(30),
|
|
14640
|
+
siteLoginStartRateLimitEnabled: exports_external.boolean().default(false),
|
|
14641
|
+
siteLoginStartPerIp: exports_external.number().int().min(0).default(5),
|
|
14642
|
+
siteLoginStartPerSubject: exports_external.number().int().min(0).default(5),
|
|
14643
|
+
siteLoginStartWindowSeconds: exports_external.number().int().min(1).default(600),
|
|
14644
|
+
siteLoginStartCooldownSeconds: exports_external.number().int().min(0).default(60),
|
|
14632
14645
|
webBuyUrlRatePerProviderPerHour: exports_external.number().int().default(20),
|
|
14633
14646
|
handoffTokenRatePerProviderPerHour: exports_external.number().int().default(60),
|
|
14634
14647
|
handoffHourlyCompletionCap: exports_external.number().int().default(120),
|
|
@@ -14648,6 +14661,7 @@ var ConfigSchema = exports_external.object({
|
|
|
14648
14661
|
lifecycleEmailSend: exports_external.boolean().default(false),
|
|
14649
14662
|
emailProviderConfigured: exports_external.boolean().default(false),
|
|
14650
14663
|
emailFrom: exports_external.string().optional(),
|
|
14664
|
+
emailPostalAddress: exports_external.string().optional(),
|
|
14651
14665
|
emailProviderUrl: exports_external.string().optional(),
|
|
14652
14666
|
hiveEnabled: exports_external.boolean().default(false),
|
|
14653
14667
|
providerOrder: exports_external.array(exports_external.string()).optional(),
|
|
@@ -14748,6 +14762,9 @@ function envBoolean(value) {
|
|
|
14748
14762
|
return;
|
|
14749
14763
|
return value === "true" || value === "1";
|
|
14750
14764
|
}
|
|
14765
|
+
function envFlagOn(value) {
|
|
14766
|
+
return ["true", "1", "on", "yes"].includes((value ?? "").trim().toLowerCase());
|
|
14767
|
+
}
|
|
14751
14768
|
function envList(value) {
|
|
14752
14769
|
if (!value)
|
|
14753
14770
|
return;
|
|
@@ -14779,6 +14796,11 @@ function loadConfig(env = process.env) {
|
|
|
14779
14796
|
maxOutputTokens: envNumber(env.MAX_OUTPUT_TOKENS),
|
|
14780
14797
|
accountsPerDayCeiling: envNumber(env.ACCOUNTS_PER_DAY_CEILING),
|
|
14781
14798
|
authRatePerIpPerHour: envNumber(env.AUTH_RATE_PER_IP_PER_HOUR),
|
|
14799
|
+
siteLoginStartRateLimitEnabled: envFlagOn(env.SITE_LOGIN_START_RATE_LIMIT),
|
|
14800
|
+
siteLoginStartPerIp: envNumber(env.SITE_LOGIN_START_PER_IP),
|
|
14801
|
+
siteLoginStartPerSubject: envNumber(env.SITE_LOGIN_START_PER_SUBJECT),
|
|
14802
|
+
siteLoginStartWindowSeconds: envNumber(env.SITE_LOGIN_START_WINDOW_SECONDS),
|
|
14803
|
+
siteLoginStartCooldownSeconds: envNumber(env.SITE_LOGIN_START_COOLDOWN_SECONDS),
|
|
14782
14804
|
webBuyUrlRatePerProviderPerHour: envNumber(env.WEB_BUY_URL_RATE_PER_PROVIDER_PER_HOUR),
|
|
14783
14805
|
handoffTokenRatePerProviderPerHour: envNumber(env.HANDOFF_TOKEN_RATE_PER_PROVIDER_PER_HOUR),
|
|
14784
14806
|
handoffHourlyCompletionCap: envNumber(env.HANDOFF_HOURLY_COMPLETION_CAP),
|
|
@@ -14798,6 +14820,7 @@ function loadConfig(env = process.env) {
|
|
|
14798
14820
|
lifecycleEmailSend: envBoolean(env.LIFECYCLE_EMAIL_SEND),
|
|
14799
14821
|
emailProviderConfigured: env.EMAIL_PROVIDER_KEY ? env.EMAIL_PROVIDER_KEY.trim().length > 0 : undefined,
|
|
14800
14822
|
emailFrom: env.EMAIL_FROM?.trim() || undefined,
|
|
14823
|
+
emailPostalAddress: env.EMAIL_POSTAL_ADDRESS?.trim() || undefined,
|
|
14801
14824
|
emailProviderUrl: env.EMAIL_PROVIDER_URL?.trim() || undefined,
|
|
14802
14825
|
hiveEnabled: envBoolean(env.HIVE_ENABLED),
|
|
14803
14826
|
providerOrder: envList(env.PROVIDER_ORDER),
|
|
@@ -14936,42 +14959,46 @@ var LIMIT_NOTICE_LABELS = {
|
|
|
14936
14959
|
concurrent_session: "another session is active",
|
|
14937
14960
|
guest_allowance: "guest trial"
|
|
14938
14961
|
};
|
|
14939
|
-
var EXTRA_CREDITS_URL = "freepi.ai/extra-credits";
|
|
14940
14962
|
var LIMIT_NOTICE_LOCAL_TIME_AFTER_SECONDS = 90 * 60;
|
|
14941
14963
|
var REFILL_CLOCK_LIMITS = new Set(["daily_cap", "global_cap", "queue_wait"]);
|
|
14942
14964
|
function formatLimitNotice(fields, opts = {}) {
|
|
14943
14965
|
const slow = fields.lane === "slow" && fields.limit === "hourly_ceiling" && fields.hourly_ceiling != null;
|
|
14944
|
-
const label = slow ? `You've used today's free allowance, so you're on the slow lane (${fields.hourly_ceiling.toLocaleString("en-US")} requests an hour).` : LIMIT_NOTICE_LABELS[fields.limit] ?? fields.limit.replace(/_/g, " ");
|
|
14945
|
-
const parts = [label];
|
|
14946
14966
|
const retry = fields.retry_after_seconds;
|
|
14947
|
-
|
|
14967
|
+
let when;
|
|
14948
14968
|
if (retry != null && retry > 0) {
|
|
14949
14969
|
const useClock = Boolean(opts.localTime) && Boolean(fields.clears_at) && retry >= LIMIT_NOTICE_LOCAL_TIME_AFTER_SECONDS;
|
|
14950
|
-
|
|
14951
|
-
const formatted = new Intl.DateTimeFormat("en-US", {
|
|
14952
|
-
timeZone: opts.timeZone,
|
|
14953
|
-
hour: "numeric",
|
|
14954
|
-
minute: "2-digit"
|
|
14955
|
-
}).format(new Date(fields.clears_at));
|
|
14956
|
-
waitBits.push(`back at ${formatted}`);
|
|
14957
|
-
} else {
|
|
14958
|
-
waitBits.push(`back in ${Math.max(1, Math.ceil(retry / 60))} min`);
|
|
14959
|
-
}
|
|
14970
|
+
when = useClock ? `at ${new Intl.DateTimeFormat("en-US", { timeZone: opts.timeZone, hour: "numeric", minute: "2-digit" }).format(new Date(fields.clears_at))}` : `in ${Math.max(1, Math.ceil(retry / 60))} min`;
|
|
14960
14971
|
}
|
|
14961
|
-
|
|
14972
|
+
const resets = () => {
|
|
14973
|
+
if (opts.copyStyle !== "treatment" || !REFILL_CLOCK_LIMITS.has(fields.limit) || !fields.clears_at)
|
|
14974
|
+
return "";
|
|
14962
14975
|
const clears = new Date(fields.clears_at);
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
}
|
|
14967
|
-
if (waitBits.length > 0)
|
|
14968
|
-
parts.push(waitBits.join(" · "));
|
|
14976
|
+
return Number.isNaN(clears.getTime()) ? "" : ` Resets ${formatRefillEt(clears)}.`;
|
|
14977
|
+
};
|
|
14978
|
+
const refillOrBuy = (lead) => `${lead} ${when ? `Credits refill ${when}, or keep going with /buy-credits.` : "Keep going with /buy-credits."}${resets()}`;
|
|
14969
14979
|
if (slow) {
|
|
14970
|
-
const
|
|
14971
|
-
|
|
14980
|
+
const label2 = `You've used today's free allowance, so you're on the slow lane (${fields.hourly_ceiling.toLocaleString("en-US")} requests an hour).`;
|
|
14981
|
+
const wait = when ? ` Back ${when} — or use` : " Use";
|
|
14982
|
+
return `${label2}${wait} /buy-credits to keep going at full speed.`;
|
|
14972
14983
|
}
|
|
14973
|
-
|
|
14974
|
-
|
|
14984
|
+
switch (fields.limit) {
|
|
14985
|
+
case "guest_allowance":
|
|
14986
|
+
return fields.remaining_credits_today > 0 ? "Guest access is busy right now." : "Your guest trial is used up.";
|
|
14987
|
+
case "daily_cap":
|
|
14988
|
+
return refillOrBuy("You've used today's free credits.");
|
|
14989
|
+
case "rolling_cap":
|
|
14990
|
+
return `You've reached your usage limit for now.${when ? ` Back ${when}.` : ""}`;
|
|
14991
|
+
case "queue_wait":
|
|
14992
|
+
return `free-pi is busy right now. ${when ? `Try again ${when}, or keep going with /buy-credits.` : "Try again soon, or keep going with /buy-credits."}${resets()}`;
|
|
14993
|
+
case "global_cap":
|
|
14994
|
+
return `free-pi has reached its shared daily limit; this isn't your limit.${when ? ` Back ${when}.` : ""}${resets()}`;
|
|
14995
|
+
}
|
|
14996
|
+
const label = LIMIT_NOTICE_LABELS[fields.limit] ?? fields.limit.replace(/_/g, " ");
|
|
14997
|
+
const bits = [label];
|
|
14998
|
+
if (when)
|
|
14999
|
+
bits.push(`back ${when}`);
|
|
15000
|
+
bits.push(`${fields.remaining_credits_today.toLocaleString("en-US")} credits left today`);
|
|
15001
|
+
return bits.join(", ");
|
|
14975
15002
|
}
|
|
14976
15003
|
// ../shared/src/version.ts
|
|
14977
15004
|
function compareVersions(a, b) {
|
|
@@ -15102,7 +15129,7 @@ var HiveClassifyResponseSchema = exports_external.object({
|
|
|
15102
15129
|
// package.json
|
|
15103
15130
|
var package_default = {
|
|
15104
15131
|
name: "free-pi-cli",
|
|
15105
|
-
version: "0.6.
|
|
15132
|
+
version: "0.6.9",
|
|
15106
15133
|
description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
|
|
15107
15134
|
license: "MIT",
|
|
15108
15135
|
type: "module",
|
|
@@ -15739,13 +15766,13 @@ async function renderMeter(deps, ctx) {
|
|
|
15739
15766
|
confirm = { addedUsd: added, turnsLeft: CONFIRM_TURNS };
|
|
15740
15767
|
if (confirm && confirm.turnsLeft > 0) {
|
|
15741
15768
|
confirm.turnsLeft--;
|
|
15742
|
-
ctx.ui.setWidget(METER_WIDGET_ID, [
|
|
15769
|
+
ctx.ui.setWidget(METER_WIDGET_ID, [theme.fg("accent", creditAddedMessage(confirm.addedUsd))]);
|
|
15743
15770
|
return;
|
|
15744
15771
|
}
|
|
15745
15772
|
confirm = undefined;
|
|
15746
15773
|
const notice = typeof me.notice === "string" ? sanitizeText(me.notice).trim() : "";
|
|
15747
15774
|
if (notice !== "") {
|
|
15748
|
-
ctx.ui.setWidget(METER_WIDGET_ID, [
|
|
15775
|
+
ctx.ui.setWidget(METER_WIDGET_ID, [theme.fg("accent", notice)]);
|
|
15749
15776
|
return;
|
|
15750
15777
|
}
|
|
15751
15778
|
if (me.lane === "fallback") {
|
|
@@ -21195,6 +21222,22 @@ function formatLimitEnvelope(env, opts) {
|
|
|
21195
21222
|
hourly_ceiling: env.hourly_ceiling
|
|
21196
21223
|
}, { localTime: true, timeZone: opts?.timeZone, copyStyle: env.copy_variant });
|
|
21197
21224
|
}
|
|
21225
|
+
var LIMIT_CODES = new Set([
|
|
21226
|
+
"guest_allowance",
|
|
21227
|
+
"daily_cap",
|
|
21228
|
+
"queue_wait",
|
|
21229
|
+
"rolling_cap",
|
|
21230
|
+
"hourly_ceiling",
|
|
21231
|
+
"concurrent",
|
|
21232
|
+
"concurrent_session",
|
|
21233
|
+
"model_requires_credits",
|
|
21234
|
+
"global_cap",
|
|
21235
|
+
"upgrade_required",
|
|
21236
|
+
"guest_unavailable",
|
|
21237
|
+
"account_review",
|
|
21238
|
+
"ads_required",
|
|
21239
|
+
"region_unavailable"
|
|
21240
|
+
]);
|
|
21198
21241
|
function createErrorNoticeExtension(opts = {}) {
|
|
21199
21242
|
const lastAt = new Map;
|
|
21200
21243
|
const now = opts.now ?? Date.now;
|
|
@@ -21213,10 +21256,10 @@ function createErrorNoticeExtension(opts = {}) {
|
|
|
21213
21256
|
if (t - (lastAt.get(env.code) ?? -Infinity) < NOTICE_DEDUPE_MS)
|
|
21214
21257
|
return;
|
|
21215
21258
|
lastAt.set(env.code, t);
|
|
21216
|
-
ctx.ui.notify(formatLimitEnvelope(env, { timeZone }), env.status >= 500 ? "error" : "warning");
|
|
21217
21259
|
const extra = opts.extraNotice?.(env);
|
|
21218
|
-
|
|
21219
|
-
|
|
21260
|
+
const text = formatLimitEnvelope(env, { timeZone }) + (extra ? `
|
|
21261
|
+
${extra}` : "");
|
|
21262
|
+
ctx.ui.notify(text, LIMIT_CODES.has(env.code) ? "info" : env.status >= 500 ? "error" : "warning");
|
|
21220
21263
|
});
|
|
21221
21264
|
}
|
|
21222
21265
|
};
|
|
@@ -21554,6 +21597,14 @@ function mergeAttribution(a, b) {
|
|
|
21554
21597
|
|
|
21555
21598
|
// src/changelog.ts
|
|
21556
21599
|
var CHANGELOG_HIGHLIGHTS = [
|
|
21600
|
+
{
|
|
21601
|
+
version: "0.6.9",
|
|
21602
|
+
highlights: [
|
|
21603
|
+
"When the guest trial runs out, sign-in opens in your browser automatically, and the link and code stay on screen.",
|
|
21604
|
+
"An expired sign-in takes you back to GitHub sign-in instead of starting a new guest trial.",
|
|
21605
|
+
"Limits (daily credits, slow lane, busy, usage limit) now show as information with a next step, not as errors."
|
|
21606
|
+
]
|
|
21607
|
+
},
|
|
21557
21608
|
{
|
|
21558
21609
|
version: "0.6.8",
|
|
21559
21610
|
highlights: [
|
|
@@ -21976,8 +22027,18 @@ class LoginDeniedError extends Error {
|
|
|
21976
22027
|
super("login_denied");
|
|
21977
22028
|
}
|
|
21978
22029
|
}
|
|
22030
|
+
|
|
22031
|
+
class DeviceCodeExpiredError extends Error {
|
|
22032
|
+
constructor() {
|
|
22033
|
+
super("expired_token");
|
|
22034
|
+
}
|
|
22035
|
+
}
|
|
22036
|
+
function isExpiredTokenPoll(body) {
|
|
22037
|
+
return body?.message === "expired_token";
|
|
22038
|
+
}
|
|
21979
22039
|
async function pollForToken(baseUrl, sessionId, interval, sleep, opts = {}) {
|
|
21980
22040
|
let consecutiveNetworkFailures = 0;
|
|
22041
|
+
let waitSeconds = Math.max(0, interval);
|
|
21981
22042
|
const now = opts.now ?? Date.now;
|
|
21982
22043
|
for (;; ) {
|
|
21983
22044
|
if (opts.deadline !== undefined && now() >= opts.deadline) {
|
|
@@ -22000,7 +22061,7 @@ async function pollForToken(baseUrl, sessionId, interval, sleep, opts = {}) {
|
|
|
22000
22061
|
if (consecutiveNetworkFailures >= 6) {
|
|
22001
22062
|
throw new Error(`token poll failed: network unreachable after ${consecutiveNetworkFailures} attempts (${err instanceof Error ? err.message : String(err)})`);
|
|
22002
22063
|
}
|
|
22003
|
-
await sleep(Math.max(
|
|
22064
|
+
await sleep(Math.max(waitSeconds, 5) * 1000);
|
|
22004
22065
|
continue;
|
|
22005
22066
|
}
|
|
22006
22067
|
if (!res.ok) {
|
|
@@ -22012,6 +22073,8 @@ async function pollForToken(baseUrl, sessionId, interval, sleep, opts = {}) {
|
|
|
22012
22073
|
throw new LoginDeniedError;
|
|
22013
22074
|
if (res.status === 410 && body?.code === "expired")
|
|
22014
22075
|
throw new LoginTimeoutError;
|
|
22076
|
+
if (isExpiredTokenPoll(body))
|
|
22077
|
+
throw new DeviceCodeExpiredError;
|
|
22015
22078
|
throw new Error(refusalMessage(res.status, body) ?? `token poll failed: HTTP ${res.status}`);
|
|
22016
22079
|
}
|
|
22017
22080
|
const parsed = AuthTokenResponseSchema.parse(await res.json());
|
|
@@ -22021,7 +22084,13 @@ async function pollForToken(baseUrl, sessionId, interval, sleep, opts = {}) {
|
|
|
22021
22084
|
throw new Error("consent_required: server did not record consent before polling");
|
|
22022
22085
|
}
|
|
22023
22086
|
const retryAfter = "retry_after" in parsed && typeof parsed.retry_after === "number" ? parsed.retry_after : 0;
|
|
22024
|
-
|
|
22087
|
+
if (retryAfter > waitSeconds) {
|
|
22088
|
+
waitSeconds = retryAfter;
|
|
22089
|
+
opts.onSlowDown?.(waitSeconds);
|
|
22090
|
+
} else if (retryAfter > 0) {
|
|
22091
|
+
opts.onSlowDown?.(waitSeconds);
|
|
22092
|
+
}
|
|
22093
|
+
await sleep(waitSeconds * 1000);
|
|
22025
22094
|
}
|
|
22026
22095
|
}
|
|
22027
22096
|
async function checkToken(baseUrl, jwt2) {
|
|
@@ -22114,6 +22183,7 @@ function clipboardCommand(platform) {
|
|
|
22114
22183
|
var CONSENT_TEXT = `
|
|
22115
22184
|
free-pi is free. In exchange, we show you ads and may train on your data.
|
|
22116
22185
|
If you want to use free-pi, you accept that. If you don't, don't use it.
|
|
22186
|
+
You must be at least 13 in the US, 16 in the EEA/UK, or 18 elsewhere.
|
|
22117
22187
|
Terms: https://freepi.ai/terms Privacy: https://freepi.ai/privacy
|
|
22118
22188
|
`.trim();
|
|
22119
22189
|
var CONSENT_VERSION = "4";
|
|
@@ -22291,6 +22361,37 @@ var LOGIN_REWARD_LINE = "Sign in with GitHub to get 15,000 free credits a day";
|
|
|
22291
22361
|
var LOGIN_WAITING_LINE = "Waiting for GitHub…";
|
|
22292
22362
|
var LOGIN_TIMEOUT_LINE = "GitHub sign-in timed out. Run /login to try again.";
|
|
22293
22363
|
var BROWSER_FAILED_LINE = "Couldn't open a browser here. Open the URL above yourself and enter the code.";
|
|
22364
|
+
var LOGIN_CODE_EXPIRED_LINE = "That code expired. Enter this new one before it times out.";
|
|
22365
|
+
var LOGIN_CODE_EXPIRY_HINT = "Enter the code on GitHub before it expires.";
|
|
22366
|
+
var MAX_DEVICE_CODE_REMINTS = 2;
|
|
22367
|
+
function formatRemaining(seconds) {
|
|
22368
|
+
const s = Math.max(0, Math.floor(seconds));
|
|
22369
|
+
if (s >= 90)
|
|
22370
|
+
return `${Math.round(s / 60)} min`;
|
|
22371
|
+
if (s >= 60)
|
|
22372
|
+
return "1 min";
|
|
22373
|
+
if (s > 0)
|
|
22374
|
+
return `${s} sec`;
|
|
22375
|
+
return "0 sec";
|
|
22376
|
+
}
|
|
22377
|
+
function formatCodeExpiryLine(expiresInSeconds) {
|
|
22378
|
+
return ` Code expires in ${formatRemaining(expiresInSeconds)}. ${LOGIN_CODE_EXPIRY_HINT}`;
|
|
22379
|
+
}
|
|
22380
|
+
function formatWaitingLine(expiresInSeconds) {
|
|
22381
|
+
return `${LOGIN_WAITING_LINE} code expires in ${formatRemaining(expiresInSeconds)}.`;
|
|
22382
|
+
}
|
|
22383
|
+
function deviceBrowserUrl(device) {
|
|
22384
|
+
if (device.verification_uri_complete?.trim())
|
|
22385
|
+
return device.verification_uri_complete.trim();
|
|
22386
|
+
try {
|
|
22387
|
+
const url2 = new URL(device.verification_uri);
|
|
22388
|
+
if (!url2.searchParams.has("user_code"))
|
|
22389
|
+
url2.searchParams.set("user_code", device.user_code);
|
|
22390
|
+
return url2.toString();
|
|
22391
|
+
} catch {
|
|
22392
|
+
return device.verification_uri;
|
|
22393
|
+
}
|
|
22394
|
+
}
|
|
22294
22395
|
function formatDeviceCodePrompt(device, variant) {
|
|
22295
22396
|
const value = isHandoffTreatment(variant) ? LOGIN_VALUE_LINE : LOGIN_REWARD_LINE;
|
|
22296
22397
|
return [
|
|
@@ -22300,12 +22401,51 @@ function formatDeviceCodePrompt(device, variant) {
|
|
|
22300
22401
|
"",
|
|
22301
22402
|
` Open ${device.verification_uri}`,
|
|
22302
22403
|
` Enter code: ${device.user_code}`,
|
|
22404
|
+
formatCodeExpiryLine(device.expires_in ?? 900),
|
|
22303
22405
|
""
|
|
22304
22406
|
].join(`
|
|
22305
22407
|
`);
|
|
22306
22408
|
}
|
|
22307
22409
|
async function runDeviceLogin(deps, attribution = {}) {
|
|
22410
|
+
let remints = 0;
|
|
22411
|
+
let lastSessionId;
|
|
22412
|
+
for (;; ) {
|
|
22413
|
+
try {
|
|
22414
|
+
return await runDeviceLoginOnce(deps, attribution, {
|
|
22415
|
+
reminted: remints > 0,
|
|
22416
|
+
onSession: (id) => {
|
|
22417
|
+
lastSessionId = id;
|
|
22418
|
+
}
|
|
22419
|
+
});
|
|
22420
|
+
} catch (err) {
|
|
22421
|
+
const expired = err instanceof DeviceCodeExpiredError || err instanceof LoginTimeoutError;
|
|
22422
|
+
if (!expired || remints >= MAX_DEVICE_CODE_REMINTS) {
|
|
22423
|
+
throw err instanceof DeviceCodeExpiredError ? new LoginTimeoutError : err;
|
|
22424
|
+
}
|
|
22425
|
+
if (lastSessionId) {
|
|
22426
|
+
await reportFunnelEvent(deps.baseUrl, "device_code_expired", {
|
|
22427
|
+
sessionId: lastSessionId,
|
|
22428
|
+
jwt: deps.jwt,
|
|
22429
|
+
fetchImpl: deps.fetchImpl
|
|
22430
|
+
});
|
|
22431
|
+
}
|
|
22432
|
+
remints += 1;
|
|
22433
|
+
deps.log(`
|
|
22434
|
+
${LOGIN_CODE_EXPIRED_LINE}
|
|
22435
|
+
`);
|
|
22436
|
+
}
|
|
22437
|
+
}
|
|
22438
|
+
}
|
|
22439
|
+
async function runDeviceLoginOnce(deps, attribution, once) {
|
|
22308
22440
|
const device = await startDeviceFlow(deps.baseUrl);
|
|
22441
|
+
once.onSession(device.session_id);
|
|
22442
|
+
if (once.reminted) {
|
|
22443
|
+
await reportFunnelEvent(deps.baseUrl, "device_code_reminted", {
|
|
22444
|
+
sessionId: device.session_id,
|
|
22445
|
+
jwt: deps.jwt,
|
|
22446
|
+
fetchImpl: deps.fetchImpl
|
|
22447
|
+
});
|
|
22448
|
+
}
|
|
22309
22449
|
deps.log(formatDeviceCodePrompt(device, deps.variant));
|
|
22310
22450
|
if (deps.credentialsPath) {
|
|
22311
22451
|
await savePendingLogin(deps.credentialsPath, {
|
|
@@ -22319,10 +22459,12 @@ async function runDeviceLogin(deps, attribution = {}) {
|
|
|
22319
22459
|
if (copied)
|
|
22320
22460
|
deps.log(` (code copied to clipboard)
|
|
22321
22461
|
`);
|
|
22322
|
-
|
|
22462
|
+
const expiresIn = device.expires_in ?? 900;
|
|
22463
|
+
deps.log(formatWaitingLine(expiresIn));
|
|
22464
|
+
const openUrl = deviceBrowserUrl(device);
|
|
22323
22465
|
let browserOpened = false;
|
|
22324
22466
|
try {
|
|
22325
|
-
browserOpened = await deps.openBrowser(
|
|
22467
|
+
browserOpened = await deps.openBrowser(openUrl) !== false;
|
|
22326
22468
|
} catch {
|
|
22327
22469
|
browserOpened = false;
|
|
22328
22470
|
}
|
|
@@ -22336,16 +22478,23 @@ async function runDeviceLogin(deps, attribution = {}) {
|
|
|
22336
22478
|
deps.log(copied ? BROWSER_FAILED_LINE : `${BROWSER_FAILED_LINE} ${HEADLESS_FALLBACK_LINE}`);
|
|
22337
22479
|
}
|
|
22338
22480
|
await submitConsent(deps.baseUrl, device.session_id, CONSENT_VERSION, attribution);
|
|
22339
|
-
const
|
|
22340
|
-
const
|
|
22341
|
-
|
|
22342
|
-
|
|
22343
|
-
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22481
|
+
const deadline = (deps.now ?? Date.now)() + expiresIn * 1000;
|
|
22482
|
+
const token = await pollForToken(deps.baseUrl, device.session_id, device.interval, deps.sleep, {
|
|
22483
|
+
deadline,
|
|
22484
|
+
now: deps.now,
|
|
22485
|
+
jwt: deps.jwt,
|
|
22486
|
+
fetchImpl: deps.fetchImpl,
|
|
22487
|
+
onSlowDown: () => {
|
|
22488
|
+
reportFunnelEvent(deps.baseUrl, "device_poll_slow_down", {
|
|
22489
|
+
sessionId: device.session_id,
|
|
22490
|
+
jwt: deps.jwt,
|
|
22491
|
+
fetchImpl: deps.fetchImpl
|
|
22492
|
+
});
|
|
22493
|
+
}
|
|
22494
|
+
});
|
|
22495
|
+
if (deps.credentialsPath)
|
|
22496
|
+
await clearPendingLogin(deps.credentialsPath);
|
|
22497
|
+
return token;
|
|
22349
22498
|
}
|
|
22350
22499
|
var CONNECT_BROWSER_FAILED_LINE = "Couldn't open a browser here, so using the GitHub device code instead.";
|
|
22351
22500
|
var CONNECT_FALLBACK_LINE = "Couldn't start the browser sign-in, so using the GitHub device code instead.";
|
|
@@ -22566,7 +22715,25 @@ async function openPrivacyPolicy(opts, ctx) {
|
|
|
22566
22715
|
function resolveHandoffVariant(opts) {
|
|
22567
22716
|
return typeof opts.variant === "function" ? opts.variant() : opts.variant;
|
|
22568
22717
|
}
|
|
22569
|
-
|
|
22718
|
+
var LOGIN_ATTEMPT_MAX_MS = 900000;
|
|
22719
|
+
var loginAttempt;
|
|
22720
|
+
async function runLogin(opts, ctx, lead) {
|
|
22721
|
+
const startedAt = (opts.now ?? Date.now)();
|
|
22722
|
+
if (loginAttempt && startedAt - loginAttempt.startedAt < LOGIN_ATTEMPT_MAX_MS)
|
|
22723
|
+
return false;
|
|
22724
|
+
const attempt = { startedAt };
|
|
22725
|
+
loginAttempt = attempt;
|
|
22726
|
+
try {
|
|
22727
|
+
return await runLoginUnguarded(opts, ctx, lead);
|
|
22728
|
+
} finally {
|
|
22729
|
+
if (loginAttempt === attempt)
|
|
22730
|
+
loginAttempt = undefined;
|
|
22731
|
+
}
|
|
22732
|
+
}
|
|
22733
|
+
async function runLoginUnguarded(opts, ctx, lead) {
|
|
22734
|
+
const lines = lead ? [lead] : [];
|
|
22735
|
+
if (lead)
|
|
22736
|
+
ctx.ui.notify(lead, "info");
|
|
22570
22737
|
try {
|
|
22571
22738
|
const attribution = opts.agentDir ? await loadAttribution(getAttributionPath(opts.agentDir)) : {};
|
|
22572
22739
|
const variant = resolveHandoffVariant(opts);
|
|
@@ -22574,7 +22741,11 @@ async function runLogin(opts, ctx) {
|
|
|
22574
22741
|
baseUrl: opts.baseUrl,
|
|
22575
22742
|
openBrowser: opts.openBrowserImpl ?? openBrowser,
|
|
22576
22743
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
22577
|
-
log: (message) =>
|
|
22744
|
+
log: (message) => {
|
|
22745
|
+
lines.push(message.trim());
|
|
22746
|
+
ctx.ui.notify(lines.filter(Boolean).join(`
|
|
22747
|
+
`), "info");
|
|
22748
|
+
},
|
|
22578
22749
|
jwt: await opts.getToken(),
|
|
22579
22750
|
fetchImpl: opts.fetchImpl,
|
|
22580
22751
|
variant,
|
|
@@ -22584,31 +22755,30 @@ async function runLogin(opts, ctx) {
|
|
|
22584
22755
|
await saveJwt(opts.credentialsPath, token);
|
|
22585
22756
|
opts.onLogin?.(token);
|
|
22586
22757
|
ctx.ui.notify(isHandoffTreatment(variant) ? SIGNED_IN_CONTINUE_LINE : "Signed in. You now have 15,000 free credits a day, plus a one-time comeback bonus.", "info");
|
|
22758
|
+
return true;
|
|
22587
22759
|
} catch (err) {
|
|
22588
22760
|
if (err instanceof LoginTimeoutError) {
|
|
22589
|
-
ctx.ui.notify(LOGIN_TIMEOUT_LINE, "
|
|
22590
|
-
return;
|
|
22761
|
+
ctx.ui.notify(LOGIN_TIMEOUT_LINE, "info");
|
|
22762
|
+
return false;
|
|
22591
22763
|
}
|
|
22592
22764
|
if (err instanceof LoginDeniedError) {
|
|
22593
|
-
ctx.ui.notify(LOGIN_DENIED_LINE, "
|
|
22594
|
-
return;
|
|
22765
|
+
ctx.ui.notify(LOGIN_DENIED_LINE, "info");
|
|
22766
|
+
return false;
|
|
22595
22767
|
}
|
|
22596
22768
|
const reason = err instanceof Error && err.message ? ` (${err.message})` : "";
|
|
22597
22769
|
ctx.ui.notify(`Couldn't finish GitHub sign-in${reason}. Run /login to try again.`, "error");
|
|
22770
|
+
return false;
|
|
22598
22771
|
}
|
|
22599
22772
|
}
|
|
22600
22773
|
function installLoginHandler(mode, opts) {
|
|
22601
22774
|
const m = mode;
|
|
22602
22775
|
mode.handleLoginCommand = () => {
|
|
22603
|
-
const lines = [];
|
|
22604
22776
|
const notify2 = (message, type) => {
|
|
22605
22777
|
if (type === "error")
|
|
22606
22778
|
return m.showError(message);
|
|
22607
22779
|
if (type === "warning")
|
|
22608
22780
|
return m.showWarning(message);
|
|
22609
|
-
|
|
22610
|
-
m.showStatus(lines.join(`
|
|
22611
|
-
`));
|
|
22781
|
+
m.showStatus(message);
|
|
22612
22782
|
};
|
|
22613
22783
|
return runLogin(opts, { ui: { notify: notify2 } });
|
|
22614
22784
|
};
|
|
@@ -22727,14 +22897,24 @@ function loadRea(pi, opts, ctx) {
|
|
|
22727
22897
|
}
|
|
22728
22898
|
ctx.ui.notify("Loading REA (reverse-engineering tools) for this session. The first run downloads rea-agents, so it can take a minute. Deep native analysis needs your own Hopper, Ghidra, or IDA install.", "info");
|
|
22729
22899
|
}
|
|
22900
|
+
var GUEST_WALL_LINE = "Your guest trial is used up. Opening GitHub sign-in in your browser… (15,000 free credits a day)";
|
|
22901
|
+
var GUEST_BUSY_LINE = "Guest access is busy right now. Opening GitHub sign-in in your browser… (15,000 free credits a day)";
|
|
22902
|
+
var GUEST_UNAVAILABLE_LINE = "Sign in with GitHub to keep going. Opening your browser… (15,000 free credits a day)";
|
|
22730
22903
|
function createGuestLoginExtension(opts) {
|
|
22731
22904
|
let started = false;
|
|
22905
|
+
let inFlight = false;
|
|
22906
|
+
let signedIn = false;
|
|
22732
22907
|
let nearWallWarned = false;
|
|
22733
|
-
const start = (ctx) => {
|
|
22908
|
+
const start = (ctx, line) => {
|
|
22734
22909
|
started = true;
|
|
22910
|
+
inFlight = true;
|
|
22735
22911
|
const variant = resolveHandoffVariant(opts);
|
|
22736
|
-
|
|
22737
|
-
runLogin(opts, ctx)
|
|
22912
|
+
const lead = line ?? (isHandoffTreatment(variant) ? LOGIN_VALUE_LINE : LOGIN_REWARD_LINE);
|
|
22913
|
+
runLogin(opts, ctx, lead).then((ok) => {
|
|
22914
|
+
signedIn = ok;
|
|
22915
|
+
}).catch(() => {}).finally(() => {
|
|
22916
|
+
inFlight = false;
|
|
22917
|
+
});
|
|
22738
22918
|
};
|
|
22739
22919
|
return {
|
|
22740
22920
|
name: "free-pi-guest-login",
|
|
@@ -22743,8 +22923,12 @@ function createGuestLoginExtension(opts) {
|
|
|
22743
22923
|
if (!opts.isGuest?.())
|
|
22744
22924
|
return;
|
|
22745
22925
|
const msg = event.message;
|
|
22746
|
-
|
|
22747
|
-
|
|
22926
|
+
const envelope = msg?.stopReason === "error" ? parseErrorEnvelope(msg.errorMessage) : undefined;
|
|
22927
|
+
if (envelope && (envelope.code === "guest_allowance" || envelope.code === "guest_unavailable" || envelope.prompt === "github_signin")) {
|
|
22928
|
+
if (!inFlight && !signedIn) {
|
|
22929
|
+
const busy = envelope.code === "guest_allowance" && (envelope.remaining_credits_today ?? 0) > 0;
|
|
22930
|
+
start(ctx, envelope.code === "guest_unavailable" ? GUEST_UNAVAILABLE_LINE : busy ? GUEST_BUSY_LINE : GUEST_WALL_LINE);
|
|
22931
|
+
}
|
|
22748
22932
|
return;
|
|
22749
22933
|
}
|
|
22750
22934
|
if (started || nearWallWarned || !isHandoffTreatment(resolveHandoffVariant(opts)))
|
|
@@ -25397,32 +25581,56 @@ async function resolveAttribution(agentDir, argv) {
|
|
|
25397
25581
|
await saveAttribution(getAttributionPath(agentDir), merged);
|
|
25398
25582
|
return { attribution: merged };
|
|
25399
25583
|
}
|
|
25400
|
-
|
|
25401
|
-
|
|
25402
|
-
if ("
|
|
25403
|
-
|
|
25584
|
+
var GUEST_SIGNIN_PROMPT = "You're using free-pi as a guest. Press Enter to sign in with GitHub (15,000 free credits a day), or Esc to keep going as a guest.";
|
|
25585
|
+
function parseGuestSigninKey(raw) {
|
|
25586
|
+
if (raw === "\r" || raw === `
|
|
25587
|
+
`)
|
|
25588
|
+
return "signin";
|
|
25589
|
+
if (raw === "\x1B")
|
|
25590
|
+
return "guest";
|
|
25591
|
+
if (raw === "\x03")
|
|
25592
|
+
return "aborted";
|
|
25593
|
+
return;
|
|
25594
|
+
}
|
|
25595
|
+
async function promptGuestSigninInteractive() {
|
|
25596
|
+
let prompt = `
|
|
25597
|
+
${GUEST_SIGNIN_PROMPT}
|
|
25598
|
+
`;
|
|
25599
|
+
for (;; ) {
|
|
25600
|
+
const choice = parseGuestSigninKey(await readOneKeypress(prompt));
|
|
25601
|
+
prompt = "";
|
|
25602
|
+
if (choice)
|
|
25603
|
+
return choice;
|
|
25404
25604
|
}
|
|
25605
|
+
}
|
|
25606
|
+
function storedTokenKind(jwt2) {
|
|
25405
25607
|
try {
|
|
25406
|
-
const
|
|
25407
|
-
|
|
25408
|
-
|
|
25409
|
-
|
|
25410
|
-
|
|
25411
|
-
|
|
25412
|
-
credentialsPath: deps.credentialsPath
|
|
25413
|
-
}, resolved.attribution ?? {}, { forceDevice: argv.includes("--device-login"), env: deps.env, platform: deps.platform });
|
|
25414
|
-
await saveJwt(deps.credentialsPath, token);
|
|
25415
|
-
return token;
|
|
25416
|
-
} catch (err) {
|
|
25417
|
-
if (err instanceof LoginTimeoutError) {
|
|
25418
|
-
deps.log(LOGIN_TIMEOUT_LINE);
|
|
25419
|
-
}
|
|
25420
|
-
if (err instanceof LoginDeniedError) {
|
|
25421
|
-
deps.log(LOGIN_DENIED_LINE);
|
|
25422
|
-
}
|
|
25423
|
-
throw err;
|
|
25608
|
+
const claims = JSON.parse(Buffer.from(jwt2.split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
25609
|
+
if (typeof claims !== "object" || claims === null)
|
|
25610
|
+
return "unknown";
|
|
25611
|
+
return claims.guest === true ? "guest" : "github";
|
|
25612
|
+
} catch {
|
|
25613
|
+
return "unknown";
|
|
25424
25614
|
}
|
|
25425
25615
|
}
|
|
25616
|
+
async function loginFlow(deps, argv = [], priorJwt) {
|
|
25617
|
+
const resolved = await resolveAttribution(deps.agentDir, argv);
|
|
25618
|
+
if ("error" in resolved && resolved.error) {
|
|
25619
|
+
throw new Error(resolved.error);
|
|
25620
|
+
}
|
|
25621
|
+
const token = await runLoginAuto({
|
|
25622
|
+
baseUrl: deps.baseUrl,
|
|
25623
|
+
openBrowser: deps.openBrowser,
|
|
25624
|
+
sleep: deps.sleep,
|
|
25625
|
+
log: deps.log,
|
|
25626
|
+
jwt: priorJwt ?? await loadJwt(deps.credentialsPath),
|
|
25627
|
+
credentialsPath: deps.credentialsPath
|
|
25628
|
+
}, resolved.attribution ?? {}, { forceDevice: argv.includes("--device-login"), env: deps.env, platform: deps.platform });
|
|
25629
|
+
await saveJwt(deps.credentialsPath, token);
|
|
25630
|
+
return token;
|
|
25631
|
+
}
|
|
25632
|
+
var SIGNIN_UNFINISHED_LINE = "Sign-in didn't finish. Run npx free-pi-cli again when you're ready.";
|
|
25633
|
+
var DECLINED_CALM_LINE = "OK, free-pi won't start. Run it again if you change your mind.";
|
|
25426
25634
|
function validateSessionId(value) {
|
|
25427
25635
|
try {
|
|
25428
25636
|
SessionManager2.inMemory(process.cwd(), { id: value });
|
|
@@ -25498,6 +25706,12 @@ ${FINISH_SIGNIN_LINE}
|
|
|
25498
25706
|
updateLatest = handled.updateLatest;
|
|
25499
25707
|
versionHandled = true;
|
|
25500
25708
|
}
|
|
25709
|
+
const interactive = deps.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
25710
|
+
const canPrompt = interactive && !resumeFlags.hasPrompt && !argv.some((a) => a === "-p" || a === "--print");
|
|
25711
|
+
let rejectedJwt;
|
|
25712
|
+
let rejectedKind = "unknown";
|
|
25713
|
+
let startedGuestThisRun = false;
|
|
25714
|
+
let signedInAfterExpiry = false;
|
|
25501
25715
|
let guestHandoffVariant;
|
|
25502
25716
|
let showFirstTask = false;
|
|
25503
25717
|
let consentCurrent = false;
|
|
@@ -25507,8 +25721,10 @@ ${FINISH_SIGNIN_LINE}
|
|
|
25507
25721
|
consentCurrent = serverConsent === CONSENT_VERSION;
|
|
25508
25722
|
if (serverConsent !== undefined && serverConsent !== CONSENT_VERSION) {
|
|
25509
25723
|
if (!await deps.promptConsent(REPROMPT_CONSENT_TEXT)) {
|
|
25510
|
-
|
|
25511
|
-
|
|
25724
|
+
if (!interactive)
|
|
25725
|
+
return 1;
|
|
25726
|
+
deps.log(DECLINED_CALM_LINE);
|
|
25727
|
+
return 0;
|
|
25512
25728
|
}
|
|
25513
25729
|
consentCurrent = true;
|
|
25514
25730
|
try {
|
|
@@ -25520,6 +25736,8 @@ ${FINISH_SIGNIN_LINE}
|
|
|
25520
25736
|
}
|
|
25521
25737
|
} catch (err) {
|
|
25522
25738
|
if (err instanceof UnauthorizedError) {
|
|
25739
|
+
rejectedKind = storedTokenKind(jwt2);
|
|
25740
|
+
rejectedJwt = jwt2;
|
|
25523
25741
|
await clearJwt(deps.credentialsPath);
|
|
25524
25742
|
jwt2 = null;
|
|
25525
25743
|
}
|
|
@@ -25528,9 +25746,45 @@ ${FINISH_SIGNIN_LINE}
|
|
|
25528
25746
|
if (!jwt2) {
|
|
25529
25747
|
const accepted = await deps.promptConsent();
|
|
25530
25748
|
if (!accepted) {
|
|
25531
|
-
|
|
25532
|
-
|
|
25749
|
+
if (!interactive)
|
|
25750
|
+
return 1;
|
|
25751
|
+
deps.log(DECLINED_CALM_LINE);
|
|
25752
|
+
return 0;
|
|
25753
|
+
}
|
|
25754
|
+
if (canPrompt && rejectedKind !== "unknown") {
|
|
25755
|
+
try {
|
|
25756
|
+
if (rejectedKind === "github") {
|
|
25757
|
+
deps.log(`
|
|
25758
|
+
Your free-pi sign-in has expired. Signing in with GitHub again.
|
|
25759
|
+
`);
|
|
25760
|
+
}
|
|
25761
|
+
const choice = rejectedKind === "github" ? "signin" : await (deps.promptGuestSignin ?? promptGuestSigninInteractive)();
|
|
25762
|
+
if (choice === "aborted") {
|
|
25763
|
+
deps.log("Aborted.");
|
|
25764
|
+
return 1;
|
|
25765
|
+
}
|
|
25766
|
+
if (choice === "signin") {
|
|
25767
|
+
jwt2 = await loginFlow(deps, argv, rejectedKind === "guest" ? rejectedJwt : undefined);
|
|
25768
|
+
consentCurrent = true;
|
|
25769
|
+
signedInAfterExpiry = true;
|
|
25770
|
+
}
|
|
25771
|
+
} catch (err) {
|
|
25772
|
+
if (rejectedKind === "github") {
|
|
25773
|
+
if (err instanceof LoginTimeoutError || err instanceof LoginDeniedError) {
|
|
25774
|
+
deps.log(SIGNIN_UNFINISHED_LINE);
|
|
25775
|
+
return 0;
|
|
25776
|
+
}
|
|
25777
|
+
const reason = err instanceof Error && err.message ? err.message : "unknown error";
|
|
25778
|
+
deps.log(`Couldn't finish GitHub sign-in: ${reason}. Run npx free-pi-cli again to retry.`);
|
|
25779
|
+
return 1;
|
|
25780
|
+
}
|
|
25781
|
+
deps.log(`
|
|
25782
|
+
Couldn't finish GitHub sign-in. Continuing as a guest.
|
|
25783
|
+
`);
|
|
25784
|
+
}
|
|
25533
25785
|
}
|
|
25786
|
+
}
|
|
25787
|
+
if (!jwt2) {
|
|
25534
25788
|
showIntro(deps.log);
|
|
25535
25789
|
const resolved = await resolveAttribution(deps.agentDir, argv);
|
|
25536
25790
|
if ("error" in resolved && resolved.error) {
|
|
@@ -25542,6 +25796,7 @@ ${FINISH_SIGNIN_LINE}
|
|
|
25542
25796
|
const guest = await startGuestSession(deps.baseUrl, CONSENT_VERSION, attribution);
|
|
25543
25797
|
await saveJwt(deps.credentialsPath, guest.token);
|
|
25544
25798
|
jwt2 = guest.token;
|
|
25799
|
+
startedGuestThisRun = true;
|
|
25545
25800
|
deps.log(isHandoffTreatment(guest.guestHandoffVariant) ? `
|
|
25546
25801
|
You're on a short guest trial — ads pay for it. ${LOGIN_VALUE_LINE}
|
|
25547
25802
|
` : `
|
|
@@ -25560,11 +25815,19 @@ You're on a short guest trial — ads pay for it. Sign in with GitHub anytime (/
|
|
|
25560
25815
|
deps.log(`
|
|
25561
25816
|
Guest trial is not available right now.
|
|
25562
25817
|
`);
|
|
25563
|
-
|
|
25818
|
+
try {
|
|
25819
|
+
jwt2 = await loginFlow(deps, argv);
|
|
25820
|
+
} catch (loginErr) {
|
|
25821
|
+
if (loginErr instanceof LoginTimeoutError || loginErr instanceof LoginDeniedError) {
|
|
25822
|
+
deps.log(SIGNIN_UNFINISHED_LINE);
|
|
25823
|
+
return 0;
|
|
25824
|
+
}
|
|
25825
|
+
throw loginErr;
|
|
25826
|
+
}
|
|
25564
25827
|
}
|
|
25565
25828
|
consentCurrent = true;
|
|
25566
25829
|
}
|
|
25567
|
-
if (!hadJwt)
|
|
25830
|
+
if (!hadJwt || signedInAfterExpiry)
|
|
25568
25831
|
versionCheck = await deps.checkClientVersion(deps.baseUrl, CLI_VERSION, jwt2);
|
|
25569
25832
|
if (!versionHandled && versionCheck.action !== "ok") {
|
|
25570
25833
|
const handled = await handleVersionAction(deps, versionCheck);
|
|
@@ -25577,13 +25840,37 @@ Guest trial is not available right now.
|
|
|
25577
25840
|
deps.log(whatsNew);
|
|
25578
25841
|
if (versionCheck.notice)
|
|
25579
25842
|
deps.log(versionCheck.notice);
|
|
25843
|
+
let me = await fetchMe2(deps.baseUrl, jwt2).catch(() => null);
|
|
25844
|
+
if (me?.guest && !startedGuestThisRun && canPrompt && consentCurrent) {
|
|
25845
|
+
try {
|
|
25846
|
+
const choice = await (deps.promptGuestSignin ?? promptGuestSigninInteractive)();
|
|
25847
|
+
if (choice === "aborted") {
|
|
25848
|
+
deps.log("Aborted.");
|
|
25849
|
+
return 1;
|
|
25850
|
+
}
|
|
25851
|
+
if (choice === "signin") {
|
|
25852
|
+
jwt2 = await loginFlow(deps, argv);
|
|
25853
|
+
me = await fetchMe2(deps.baseUrl, jwt2).catch(() => null);
|
|
25854
|
+
versionCheck = await deps.checkClientVersion(deps.baseUrl, CLI_VERSION, jwt2).catch(() => versionCheck);
|
|
25855
|
+
if (versionCheck.action !== "ok") {
|
|
25856
|
+
const handled = await handleVersionAction(deps, versionCheck);
|
|
25857
|
+
if (handled.code !== undefined)
|
|
25858
|
+
return handled.code;
|
|
25859
|
+
updateLatest = handled.updateLatest;
|
|
25860
|
+
}
|
|
25861
|
+
}
|
|
25862
|
+
} catch {
|
|
25863
|
+
deps.log(`
|
|
25864
|
+
Couldn't finish GitHub sign-in. Continuing as a guest.
|
|
25865
|
+
`);
|
|
25866
|
+
}
|
|
25867
|
+
}
|
|
25580
25868
|
let getGravityContext;
|
|
25581
25869
|
if (consentCurrent) {
|
|
25582
25870
|
try {
|
|
25583
25871
|
getGravityContext = deps.startGravityPixel?.(jwt2);
|
|
25584
25872
|
} catch {}
|
|
25585
25873
|
}
|
|
25586
|
-
const me = await fetchMe2(deps.baseUrl, jwt2).catch(() => null);
|
|
25587
25874
|
if (me)
|
|
25588
25875
|
updateAllowanceCache(me);
|
|
25589
25876
|
guestHandoffVariant = me?.experiments?.guest_handoff ?? guestHandoffVariant;
|
|
@@ -25611,7 +25898,6 @@ ${creditsBack}`);
|
|
|
25611
25898
|
const experiment = versionCheck.experiments?.[RESUME_ON_LAUNCH_EXPERIMENT];
|
|
25612
25899
|
const variant = experiment?.variant === "treatment" ? "treatment" : "control";
|
|
25613
25900
|
const recentHours = recentHoursFromEnv(process.env, experiment?.recent_hours);
|
|
25614
|
-
const interactive = deps.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
25615
25901
|
if (!session && !resumeFlags.startNew && !resumeFlags.hasPrompt && variant === "treatment" && interactive) {
|
|
25616
25902
|
const latest = await lookupLatest(process.cwd(), deps.agentDir);
|
|
25617
25903
|
const now = deps.now?.() ?? new Date;
|