free-pi-cli 0.6.7 → 0.6.8

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 CHANGED
@@ -30,4 +30,4 @@ if (err) {
30
30
  console.error(err);
31
31
  process.exit(1);
32
32
  }
33
- await import("./main-tm302552.js");
33
+ await import("./main-tyjwqhr5.js");
@@ -14391,7 +14391,10 @@ var AuthTokenPendingSchema = exports_external.object({
14391
14391
  status: exports_external.literal("pending"),
14392
14392
  retry_after: exports_external.number().optional()
14393
14393
  });
14394
- var AuthTokenIssuedSchema = exports_external.object({ token: exports_external.string() });
14394
+ var AuthTokenIssuedSchema = exports_external.object({
14395
+ token: exports_external.string(),
14396
+ guest_bonus_credits_granted: exports_external.number().int().optional()
14397
+ });
14395
14398
  var AuthTokenConsentRequiredSchema = exports_external.object({
14396
14399
  code: exports_external.literal("consent_required"),
14397
14400
  message: exports_external.string()
@@ -14437,7 +14440,9 @@ var GuestStartResponseSchema = exports_external.object({
14437
14440
  guest: exports_external.literal(true),
14438
14441
  allowance_usd: exports_external.string(),
14439
14442
  remaining_usd: exports_external.string(),
14440
- experiments: ExperimentAssignmentSchema.optional()
14443
+ experiments: ExperimentAssignmentSchema.optional(),
14444
+ claim_code: exports_external.string().optional(),
14445
+ github_bonus_credits: exports_external.number().int().optional()
14441
14446
  });
14442
14447
  var GuestUnavailableResponseSchema = exports_external.object({
14443
14448
  code: exports_external.literal("guest_unavailable"),
@@ -14701,6 +14706,7 @@ var ConfigSchema = exports_external.object({
14701
14706
  guestIpHashRetentionDays: exports_external.number().int().default(7),
14702
14707
  returnBonusDay2Credits: exports_external.number().int().default(2000),
14703
14708
  returnBonusDay7Credits: exports_external.number().int().default(1000),
14709
+ guestGithubBonusCredits: exports_external.number().int().default(1e4),
14704
14710
  returnNudgeEmailEnabled: exports_external.boolean().default(false),
14705
14711
  referralBonusCreditsPerDay: exports_external.number().int().default(5000),
14706
14712
  referralBonusDays: exports_external.number().int().default(30),
@@ -14845,6 +14851,7 @@ function loadConfig(env = process.env) {
14845
14851
  guestIpHashRetentionDays: envStrictInt("GUEST_IP_HASH_RETENTION_DAYS", env.GUEST_IP_HASH_RETENTION_DAYS),
14846
14852
  returnBonusDay2Credits: envStrictInt("RETURN_BONUS_DAY2_CREDITS", env.RETURN_BONUS_DAY2_CREDITS),
14847
14853
  returnBonusDay7Credits: envStrictInt("RETURN_BONUS_DAY7_CREDITS", env.RETURN_BONUS_DAY7_CREDITS),
14854
+ guestGithubBonusCredits: envStrictInt("GUEST_GITHUB_BONUS_CREDITS", env.GUEST_GITHUB_BONUS_CREDITS),
14848
14855
  returnNudgeEmailEnabled: envBoolean(env.RETURN_NUDGE_EMAIL_ENABLED),
14849
14856
  referralBonusCreditsPerDay: envStrictInt("REFERRAL_BONUS_CREDITS_PER_DAY", env.REFERRAL_BONUS_CREDITS_PER_DAY),
14850
14857
  referralBonusDays: envStrictInt("REFERRAL_BONUS_DAYS", env.REFERRAL_BONUS_DAYS),
@@ -15095,7 +15102,7 @@ var HiveClassifyResponseSchema = exports_external.object({
15095
15102
  // package.json
15096
15103
  var package_default = {
15097
15104
  name: "free-pi-cli",
15098
- version: "0.6.7",
15105
+ version: "0.6.8",
15099
15106
  description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
15100
15107
  license: "MIT",
15101
15108
  type: "module",
@@ -20178,12 +20185,14 @@ function formatStats(stats) {
20178
20185
  const allowance = stats.allowance_credits;
20179
20186
  const refillAt = stats.refill_at;
20180
20187
  const lane2 = stats.lane;
20188
+ const bonus = stats.bonus_wallet_credits;
20181
20189
  const todayLine = typeof remaining === "number" && typeof allowance === "number" && typeof refillAt === "string" ? formatCreditsLeftLine(remaining, allowance, new Date(refillAt)) : `today: ${percentUsed(stats.spent_usd_today, stats.cap_usd_today)}% of your free daily allowance used`;
20182
20190
  return [
20183
20191
  `tier: ${stats.tier}`,
20184
20192
  todayLine,
20185
20193
  ...lane2 === "fallback" ? [SLOW_LANE_METER_LINE] : [],
20186
20194
  ...typeof credits2 === "number" ? [`credit: ${credits2.toLocaleString("en-US")} credits remaining`] : [],
20195
+ ...typeof bonus === "number" && bonus > 0 ? [`bonus: ${bonus.toLocaleString("en-US")} credits remaining`] : [],
20187
20196
  `today tokens: ${stats.prompt_tokens_today} prompt / ${stats.completion_tokens_today} completion`,
20188
20197
  `lifetime: ${stats.lifetime.prompt_tokens} prompt / ${stats.lifetime.completion_tokens} completion tokens`,
20189
20198
  "buy more credits: /buy-credits",
@@ -21213,6 +21222,88 @@ function createErrorNoticeExtension(opts = {}) {
21213
21222
  };
21214
21223
  }
21215
21224
 
21225
+ // src/upgrade-notice.ts
21226
+ var UPGRADE_NOTICE_MARKER = ": freepi_notice";
21227
+ var UPGRADE_NOTICE_TEXT = "free-pi is upgrading — short delay. Your request will continue automatically.";
21228
+ var SLOW_SERVER_HINT = "Waiting for the server — free-pi may be upgrading; your request will continue automatically.";
21229
+ var SLOW_HEADERS_MS = 8000;
21230
+ var UPGRADE_NOTICE_DEDUPE_MS = 60000;
21231
+ function isCompletionsCall(input, completionsUrl) {
21232
+ try {
21233
+ const raw = input instanceof Request ? input.url : String(input);
21234
+ const got = new URL(raw);
21235
+ const want = new URL(completionsUrl);
21236
+ return got.origin === want.origin && got.pathname === want.pathname;
21237
+ } catch {
21238
+ return false;
21239
+ }
21240
+ }
21241
+ function wrapFetchForUpgrade(base, opts) {
21242
+ return async (input, init) => {
21243
+ if (!isCompletionsCall(input, opts.completionsUrl))
21244
+ return base(input, init);
21245
+ const timer = setTimeout(opts.onSlow, opts.slowMs ?? SLOW_HEADERS_MS);
21246
+ let res;
21247
+ try {
21248
+ res = await base(input, init);
21249
+ } finally {
21250
+ clearTimeout(timer);
21251
+ }
21252
+ if (!res.body || !(res.headers.get("content-type") ?? "").includes("text/event-stream"))
21253
+ return res;
21254
+ const decoder = new TextDecoder;
21255
+ let tail = `
21256
+ `;
21257
+ let seen = false;
21258
+ const body = res.body.pipeThrough(new TransformStream({
21259
+ transform(chunk, ctl) {
21260
+ ctl.enqueue(chunk);
21261
+ if (seen)
21262
+ return;
21263
+ const text = tail + decoder.decode(chunk, { stream: true });
21264
+ if (text.includes(`
21265
+ ${UPGRADE_NOTICE_MARKER}`)) {
21266
+ seen = true;
21267
+ opts.onNotice();
21268
+ } else
21269
+ tail = text.slice(-UPGRADE_NOTICE_MARKER.length);
21270
+ }
21271
+ }));
21272
+ return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
21273
+ };
21274
+ }
21275
+ var notify;
21276
+ var lastAt = new Map;
21277
+ var WRAPPED = Symbol.for("free-pi.upgrade-notice");
21278
+ function createUpgradeNoticeExtension(opts) {
21279
+ const now = opts.now ?? Date.now;
21280
+ const show = (message) => {
21281
+ const t = now();
21282
+ if (t - (lastAt.get(message) ?? -Infinity) < UPGRADE_NOTICE_DEDUPE_MS)
21283
+ return;
21284
+ lastAt.set(message, t);
21285
+ notify?.(message);
21286
+ };
21287
+ return {
21288
+ name: "free-pi-upgrade-notice",
21289
+ factory(pi) {
21290
+ pi.on("session_start", (_event, ctx) => {
21291
+ notify = (m) => ctx.ui.notify(m, "info");
21292
+ });
21293
+ if (globalThis.fetch[WRAPPED])
21294
+ return;
21295
+ const wrapped = wrapFetchForUpgrade(globalThis.fetch, {
21296
+ completionsUrl: `${completionsBaseUrl(opts.baseUrl)}/chat/completions`,
21297
+ slowMs: opts.slowMs,
21298
+ onNotice: () => show(UPGRADE_NOTICE_TEXT),
21299
+ onSlow: () => show(SLOW_SERVER_HINT)
21300
+ });
21301
+ wrapped[WRAPPED] = true;
21302
+ globalThis.fetch = wrapped;
21303
+ }
21304
+ };
21305
+ }
21306
+
21216
21307
  // src/agent-rules.ts
21217
21308
  var AGENT_RULES = `## Working rules
21218
21309
  - When you say you will run, check, or change something, make that tool call in the same
@@ -21380,6 +21471,17 @@ var LOGIN_VALUE_LINE = "sign in free with GitHub: full daily allowance, FREE abl
21380
21471
  var GUEST_NEAR_WALL_LINE = `A few guest requests left. ${LOGIN_VALUE_LINE}`;
21381
21472
  var SIGNED_IN_CONTINUE_LINE = "Signed in. Your conversation continues — full daily allowance is unlocked.";
21382
21473
  var HEADLESS_FALLBACK_LINE = "No browser or clipboard here — open the URL and enter the code above.";
21474
+ function formatGuestBonusBox(claimCode, credits2) {
21475
+ const amount = credits2.toLocaleString("en-US");
21476
+ const rows = [
21477
+ `GUEST BONUS * code ${claimCode}`,
21478
+ `Connect GitHub with /login -> +${amount} credits`,
21479
+ "One time, on your first GitHub sign-in."
21480
+ ];
21481
+ const inner = Math.max(...rows.map((r) => r.length)) + 4;
21482
+ const edge = `+${"-".repeat(inner)}+`;
21483
+ return [edge, ...rows.map((r) => `| ${r.padEnd(inner - 2)}|`), edge];
21484
+ }
21383
21485
  function isHandoffTreatment(variant) {
21384
21486
  return variant === "treatment";
21385
21487
  }
@@ -21452,6 +21554,14 @@ function mergeAttribution(a, b) {
21452
21554
 
21453
21555
  // src/changelog.ts
21454
21556
  var CHANGELOG_HIGHLIGHTS = [
21557
+ {
21558
+ version: "0.6.8",
21559
+ highlights: [
21560
+ "During a server upgrade free-pi now says it is upgrading and that your request will continue automatically.",
21561
+ "Guest trials show a bonus code: sign in with GitHub (/login) for a one-time +10,000 credits.",
21562
+ "/usage now shows your bonus credits on their own line, matching the footer."
21563
+ ]
21564
+ },
21455
21565
  {
21456
21566
  version: "0.6.7",
21457
21567
  highlights: [
@@ -21836,7 +21946,9 @@ async function startGuestSession(baseUrl, consentVersion, attribution = {}) {
21836
21946
  allowance_usd: parsed.allowance_usd,
21837
21947
  remaining_usd: parsed.remaining_usd,
21838
21948
  guestHandoffVariant: parsed.experiments?.guest_handoff,
21839
- firstTaskVariant: parsed.experiments?.first_task
21949
+ firstTaskVariant: parsed.experiments?.first_task,
21950
+ claimCode: parsed.claim_code,
21951
+ githubBonusCredits: parsed.github_bonus_credits
21840
21952
  };
21841
21953
  }
21842
21954
  async function reportFunnelEvent(baseUrl, event, opts = {}) {
@@ -22489,7 +22601,7 @@ function installLoginHandler(mode, opts) {
22489
22601
  const m = mode;
22490
22602
  mode.handleLoginCommand = () => {
22491
22603
  const lines = [];
22492
- const notify = (message, type) => {
22604
+ const notify2 = (message, type) => {
22493
22605
  if (type === "error")
22494
22606
  return m.showError(message);
22495
22607
  if (type === "warning")
@@ -22498,7 +22610,7 @@ function installLoginHandler(mode, opts) {
22498
22610
  m.showStatus(lines.join(`
22499
22611
  `));
22500
22612
  };
22501
- return runLogin(opts, { ui: { notify } });
22613
+ return runLogin(opts, { ui: { notify: notify2 } });
22502
22614
  };
22503
22615
  }
22504
22616
  var LOGOUT_DONE_LINE = "Signed out of free-pi. Restart free-pi to sign in again.";
@@ -23452,7 +23564,7 @@ function createHiveExtension(opts) {
23452
23564
  let connectTimer;
23453
23565
  let roomWaiter;
23454
23566
  const dialogs = new Set;
23455
- const notify = (message, type = "info") => ctxRef?.ui.notify(message, type);
23567
+ const notify2 = (message, type = "info") => ctxRef?.ui.notify(message, type);
23456
23568
  function send(frame) {
23457
23569
  if (ws && ws.readyState === OPEN)
23458
23570
  ws.send(JSON.stringify(frame));
@@ -23496,13 +23608,13 @@ function createHiveExtension(opts) {
23496
23608
  const message = [notice, changes].filter(Boolean).join(`
23497
23609
  `);
23498
23610
  if (message)
23499
- notify(message, "info");
23611
+ notify2(message, "info");
23500
23612
  roomWaiter?.();
23501
23613
  roomWaiter = undefined;
23502
23614
  }
23503
23615
  async function start(ctx) {
23504
23616
  if (ws || starting) {
23505
- notify(roomUrl ? `Hive room: ${roomUrl}` : "Hive: still connecting...");
23617
+ notify2(roomUrl ? `Hive room: ${roomUrl}` : "Hive: still connecting...");
23506
23618
  return;
23507
23619
  }
23508
23620
  starting = true;
@@ -23511,7 +23623,7 @@ function createHiveExtension(opts) {
23511
23623
  token = await opts.getToken();
23512
23624
  } catch {
23513
23625
  starting = false;
23514
- notify("Hive: couldn't read your free-pi login. Try again after signing in.", "error");
23626
+ notify2("Hive: couldn't read your free-pi login. Try again after signing in.", "error");
23515
23627
  return;
23516
23628
  }
23517
23629
  starting = false;
@@ -23578,7 +23690,7 @@ Sandboxing is available: when you approve a guest's shell command you can run it
23578
23690
  clearTimeout(connectTimer);
23579
23691
  if (!settled)
23580
23692
  send({ type: "busy", settled: false });
23581
- notify(`Hive room open: ${frame.url}
23693
+ notify2(`Hive room open: ${frame.url}
23582
23694
  Guests sign in with GitHub to watch and chat. They can ask to drive; you approve each request, and risky actions still ask you.${sandboxLine()}`);
23583
23695
  updateStatus();
23584
23696
  roomWaiter?.();
@@ -23610,7 +23722,7 @@ Guests sign in with GitHub to watch and chat. They can ask to drive; you approve
23610
23722
  break;
23611
23723
  case "error":
23612
23724
  if (frame.code !== "stale")
23613
- notify(`Hive: ${frame.code}`, "warning");
23725
+ notify2(`Hive: ${frame.code}`, "warning");
23614
23726
  break;
23615
23727
  case "closed":
23616
23728
  endRoom(`Hive room closed (${frame.reason}).`);
@@ -23783,7 +23895,7 @@ ${decision.reason}`, ACTION_DIALOG_MS);
23783
23895
  handler: async (args, ctx) => {
23784
23896
  ctxRef = ctx;
23785
23897
  const [sub = "", ...rest3] = args.trim().split(/\s+/);
23786
- const noRoom = () => notify("No hive room is open. Run /hive to start one.");
23898
+ const noRoom = () => notify2("No hive room is open. Run /hive to start one.");
23787
23899
  switch (sub.toLowerCase()) {
23788
23900
  case "":
23789
23901
  return start(ctx);
@@ -23802,20 +23914,20 @@ ${decision.reason}`, ACTION_DIALOG_MS);
23802
23914
  const handle2 = (rest3[0] ?? "").replace(/^@/, "").toLowerCase();
23803
23915
  const ids = new Set(members.filter((m) => handle2 && m.handle.toLowerCase() === handle2).map((m) => m.provider_id));
23804
23916
  if (ids.size === 0)
23805
- return notify(`No guest named "${handle2}" in the room. Usage: /hive kick <handle>`);
23917
+ return notify2(`No guest named "${handle2}" in the room. Usage: /hive kick <handle>`);
23806
23918
  dropRecorded();
23807
23919
  for (const provider_id of ids) {
23808
23920
  kicked.add(provider_id);
23809
23921
  send({ type: "kick", provider_id });
23810
23922
  }
23811
- return notify(`Kicked @${handle2}. They cannot rejoin this room.`);
23923
+ return notify2(`Kicked @${handle2}. They cannot rejoin this room.`);
23812
23924
  }
23813
23925
  case "end":
23814
23926
  if (!ws)
23815
23927
  return noRoom();
23816
23928
  return endRoom("Hive room ended.", true);
23817
23929
  default:
23818
- return notify("Usage: /hive, /hive take, /hive kick <handle>, /hive end");
23930
+ return notify2("Usage: /hive, /hive take, /hive kick <handle>, /hive end");
23819
23931
  }
23820
23932
  }
23821
23933
  });
@@ -24743,6 +24855,7 @@ function buildRuntimeOptions(opts, sessionId) {
24743
24855
  imageToolExtension,
24744
24856
  visionToolExtension,
24745
24857
  errorNoticeExtension,
24858
+ createUpgradeNoticeExtension({ baseUrl: opts.baseUrl }),
24746
24859
  createOutputLimitExtension(),
24747
24860
  toolGuardExtension,
24748
24861
  commandsExtension,
@@ -25434,6 +25547,11 @@ You're on a short guest trial — ads pay for it. ${LOGIN_VALUE_LINE}
25434
25547
  ` : `
25435
25548
  You're on a short guest trial — ads pay for it. Sign in with GitHub anytime (/login) to get 15,000 free credits a day and unlock a one-time comeback bonus.
25436
25549
  `);
25550
+ if (guest.claimCode && guest.githubBonusCredits) {
25551
+ deps.log(emphasize(formatGuestBonusBox(guest.claimCode, guest.githubBonusCredits).join(`
25552
+ `)) + `
25553
+ `);
25554
+ }
25437
25555
  guestHandoffVariant = guest.guestHandoffVariant;
25438
25556
  showFirstTask = guest.firstTaskVariant === "treatment" && !resumeFlags.hasPrompt;
25439
25557
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
5
5
  "license": "MIT",
6
6
  "type": "module",