free-pi-cli 0.2.14 → 0.2.15

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-7619wn7y.js");
33
+ await import("./main-d6chy61g.js");
@@ -48,7 +48,7 @@ function openBrowser(url, platform = process.platform, spawnImpl = spawn) {
48
48
  // package.json
49
49
  var package_default = {
50
50
  name: "free-pi-cli",
51
- version: "0.2.14",
51
+ version: "0.2.15",
52
52
  description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
53
53
  license: "MIT",
54
54
  type: "module",
@@ -14599,6 +14599,7 @@ var ConfigSchema = exports_external.object({
14599
14599
  contextCharBudget: exports_external.number().int().default(800000),
14600
14600
  accountsPerDayCeiling: exports_external.number().int().default(500),
14601
14601
  authRatePerIpPerHour: exports_external.number().int().default(30),
14602
+ webBuyUrlRatePerProviderPerHour: exports_external.number().int().default(20),
14602
14603
  tokenRatePerIpPerHour: exports_external.number().int().default(3600),
14603
14604
  consentRatePerIpPerHour: exports_external.number().int().default(60),
14604
14605
  adInlineTurnFrequency: exports_external.number().int().default(5),
@@ -14664,6 +14665,7 @@ function loadConfig(env = process.env) {
14664
14665
  contextCharBudget: envNumber(env.CONTEXT_CHAR_BUDGET),
14665
14666
  accountsPerDayCeiling: envNumber(env.ACCOUNTS_PER_DAY_CEILING),
14666
14667
  authRatePerIpPerHour: envNumber(env.AUTH_RATE_PER_IP_PER_HOUR),
14668
+ webBuyUrlRatePerProviderPerHour: envNumber(env.WEB_BUY_URL_RATE_PER_PROVIDER_PER_HOUR),
14667
14669
  tokenRatePerIpPerHour: envNumber(env.TOKEN_RATE_PER_IP_PER_HOUR),
14668
14670
  consentRatePerIpPerHour: envNumber(env.CONSENT_RATE_PER_IP_PER_HOUR),
14669
14671
  adInlineTurnFrequency: envNumber(env.AD_INLINE_TURN_FREQUENCY),
@@ -14832,19 +14834,21 @@ function renderErrorLine(message, theme) {
14832
14834
 
14833
14835
  // ../pi-ads/src/banner.ts
14834
14836
  var BANNER_WIDGET_ID = "freepi-ad";
14835
- function createBannerRenderer() {
14837
+ function createBannerRenderer(opts = {}) {
14836
14838
  let lastPostedToken;
14837
14839
  return {
14838
14840
  async render(deps, ctx, config3, columnsOverride) {
14839
14841
  const ad = await fetchAdNext(deps, "banner");
14840
14842
  if (!ad) {
14841
14843
  ctx.ui.setWidget(BANNER_WIDGET_ID, undefined);
14844
+ opts.onBannerAd?.(undefined);
14842
14845
  return;
14843
14846
  }
14844
14847
  const theme = ctx.ui.theme;
14845
14848
  const columns = columnsOverride ?? process.stdout.columns ?? 80;
14846
14849
  const lines = columns >= config3.adMinColumns ? renderAdCard(ad.creative, ad.click_url, theme, columns) : [renderPlainAdLine(ad.creative, ad.click_url, theme, columns)];
14847
14850
  ctx.ui.setWidget(BANNER_WIDGET_ID, lines);
14851
+ opts.onBannerAd?.(ad.click_url);
14848
14852
  if (lastPostedToken !== ad.click_token) {
14849
14853
  lastPostedToken = ad.click_token;
14850
14854
  await postImpression(deps, ad.ad_id, ad.click_token);
@@ -14975,7 +14979,7 @@ function createAdsExtension(opts) {
14975
14979
  return {
14976
14980
  name: "free-pi-ads",
14977
14981
  factory(pi) {
14978
- const banner = createBannerRenderer();
14982
+ const banner = createBannerRenderer({ onBannerAd: opts.onBannerAd });
14979
14983
  const inline = createInlineRenderer();
14980
14984
  let bannerInterval;
14981
14985
  pi.on("session_start", async (_event, ctx) => {
@@ -19476,6 +19480,13 @@ function createToolGuardExtension(opts) {
19476
19480
 
19477
19481
  // src/changelog.ts
19478
19482
  var CHANGELOG_HIGHLIGHTS = [
19483
+ {
19484
+ version: "0.2.15",
19485
+ highlights: [
19486
+ "New startup screen: the model, a welcome line, and the five free-pi commands.",
19487
+ "/support opens today's advertiser in your browser. It grants nothing."
19488
+ ]
19489
+ },
19479
19490
  {
19480
19491
  version: "0.2.14",
19481
19492
  highlights: [
@@ -19624,6 +19635,15 @@ async function buyCredits(opts, ctx) {
19624
19635
  (opts.openBrowserImpl ?? openBrowser)(page.url);
19625
19636
  ctx.ui.notify(buyPageText(page.url), "info");
19626
19637
  }
19638
+ async function openAdvertiser(opts, ctx) {
19639
+ const url2 = opts.getAdvertiserUrl?.();
19640
+ if (!url2) {
19641
+ ctx.ui.notify("No advertiser loaded yet.", "info");
19642
+ return;
19643
+ }
19644
+ (opts.openBrowserImpl ?? openBrowser)(url2);
19645
+ ctx.ui.notify("Opening today's advertiser in your browser. Thank you for supporting free-pi.", "info");
19646
+ }
19627
19647
  async function showUsage(opts, ctx) {
19628
19648
  const r = await fetchUsageText(opts);
19629
19649
  ctx.ui.notify(r.text, r.ok ? "info" : "error");
@@ -19652,6 +19672,68 @@ function createFreePiCommandsExtension(opts) {
19652
19672
  description: "Buy more usage ($5 or $10 packs, card or USDC) — opens the buy page.",
19653
19673
  handler: (_args, ctx) => buyCredits(opts, ctx)
19654
19674
  });
19675
+ pi.registerCommand("support", {
19676
+ description: "Open today's advertiser in your browser to support free-pi.",
19677
+ handler: (_args, ctx) => openAdvertiser(opts, ctx)
19678
+ });
19679
+ }
19680
+ };
19681
+ }
19682
+
19683
+ // src/header.ts
19684
+ var COMMANDS = [
19685
+ { name: "/usage", description: "spend and remaining budget today" },
19686
+ { name: "/support", description: "visit today's advertiser" },
19687
+ { name: "/buy-credits", description: "get more usage" },
19688
+ { name: "/close-other-session", description: "free a stuck session on another machine" },
19689
+ { name: "/update", description: "get the latest free-pi" }
19690
+ ];
19691
+ var NAME_COLUMN = 24;
19692
+ var WELCOME_LINE = "Welcome to Free Pi, ad-supported inference. Please visit our advertisers to support us.";
19693
+ var EXPANDED_HINT_LINE = "esc interrupt · ctrl+c clear / exit · / commands · ! bash";
19694
+ function truncate2(text, maxWidth) {
19695
+ if (maxWidth <= 0)
19696
+ return "";
19697
+ if (text.length <= maxWidth)
19698
+ return text;
19699
+ if (maxWidth <= 1)
19700
+ return text.slice(0, maxWidth);
19701
+ return `${text.slice(0, maxWidth - 1)}…`;
19702
+ }
19703
+ function headerLines(theme, modelName, expanded, width = Number.POSITIVE_INFINITY) {
19704
+ const inner = width - 1;
19705
+ const fit = (plain, styled) => plain.length <= inner ? styled() : theme.fg("dim", truncate2(plain, inner));
19706
+ const titleRest = ` · ${modelName} · ctrl+o for help`;
19707
+ const title = fit(`free-pi${titleRest}`, () => `${theme.bold(theme.fg("accent", "free-pi"))}${theme.fg("dim", titleRest)}`);
19708
+ const commandLines = COMMANDS.map(({ name, description }) => {
19709
+ const padded = ` ${name}`.padEnd(NAME_COLUMN, " ");
19710
+ return fit(`${padded}${description}`, () => `${padded}${theme.fg("dim", description)}`);
19711
+ });
19712
+ const dim = (plain) => fit(plain, () => theme.fg("dim", plain));
19713
+ const lines = ["", title, "", dim(WELCOME_LINE), "", ...commandLines, ""];
19714
+ if (expanded)
19715
+ lines.push(dim(EXPANDED_HINT_LINE));
19716
+ return lines.map((line) => line === "" ? line : ` ${line}`);
19717
+ }
19718
+ function createHeaderExtension(opts) {
19719
+ return {
19720
+ name: "free-pi-header",
19721
+ factory(pi) {
19722
+ pi.on("session_start", (_event, ctx) => {
19723
+ ctx.ui.setHeader((tui, theme) => {
19724
+ let expanded = false;
19725
+ return {
19726
+ render(width) {
19727
+ return headerLines(theme, opts.modelName, expanded, width);
19728
+ },
19729
+ invalidate() {},
19730
+ setExpanded(next) {
19731
+ expanded = next;
19732
+ tui.requestRender();
19733
+ }
19734
+ };
19735
+ });
19736
+ });
19655
19737
  }
19656
19738
  };
19657
19739
  }
@@ -19677,6 +19759,9 @@ function catalogModelsFor(opts) {
19677
19759
  return [{ id, name: id }];
19678
19760
  }
19679
19761
  var ALLOWED_TOOL_NAMES = [...SAFE_TOOLS, USAGE_TOOL_NAME, BUY_TOOL_NAME];
19762
+ function resolveModelName(opts) {
19763
+ return opts.models?.[0]?.name || opts.model || MODEL_ID;
19764
+ }
19680
19765
  function buildRuntimeOptions(opts, sessionId) {
19681
19766
  const models = catalogModelsFor(opts);
19682
19767
  const providerExtension = {
@@ -19685,10 +19770,14 @@ function buildRuntimeOptions(opts, sessionId) {
19685
19770
  pi.registerProvider(PROVIDER_NAME, buildProviderConfig(opts.baseUrl, opts.jwt, sessionId, models));
19686
19771
  }
19687
19772
  };
19773
+ let advertiserUrl;
19688
19774
  const adsExtension = createAdsExtension({
19689
19775
  baseUrl: opts.baseUrl,
19690
19776
  getToken: () => opts.jwt,
19691
- sessionId
19777
+ sessionId,
19778
+ onBannerAd: (u) => {
19779
+ advertiserUrl = u;
19780
+ }
19692
19781
  });
19693
19782
  const usageToolExtension = createUsageToolExtension({
19694
19783
  baseUrl: opts.baseUrl,
@@ -19706,7 +19795,11 @@ function buildRuntimeOptions(opts, sessionId) {
19706
19795
  });
19707
19796
  const commandsExtension = createFreePiCommandsExtension({
19708
19797
  baseUrl: opts.baseUrl,
19709
- getToken: () => opts.jwt
19798
+ getToken: () => opts.jwt,
19799
+ getAdvertiserUrl: () => advertiserUrl
19800
+ });
19801
+ const headerExtension = createHeaderExtension({
19802
+ modelName: resolveModelName(opts)
19710
19803
  });
19711
19804
  const extensionFactories = [
19712
19805
  providerExtension,
@@ -19715,13 +19808,15 @@ function buildRuntimeOptions(opts, sessionId) {
19715
19808
  buyToolExtension,
19716
19809
  errorNoticeExtension,
19717
19810
  toolGuardExtension,
19718
- commandsExtension
19811
+ commandsExtension,
19812
+ headerExtension
19719
19813
  ];
19720
19814
  const settingsManager = SettingsManager.inMemory({
19721
19815
  defaultProvider: PROVIDER_NAME,
19722
19816
  defaultModel: models[0].id,
19723
19817
  defaultTools: [...SAFE_TOOLS],
19724
- packages: []
19818
+ packages: [],
19819
+ quietStartup: true
19725
19820
  });
19726
19821
  return {
19727
19822
  settingsManager,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
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",