free-pi-cli 0.2.9 → 0.2.11

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-wdjtzs85.js");
33
+ await import("./main-q2v4gzhd.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.9",
51
+ version: "0.2.11",
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",
@@ -63,11 +63,11 @@ var package_default = {
63
63
  node: ">=22.19.0"
64
64
  },
65
65
  scripts: {
66
- build: "bun build src/index.ts --target=node --outdir dist --splitting --external @earendil-works/pi-coding-agent --banner '#!/usr/bin/env node' && chmod +x dist/index.js",
66
+ build: "rm -rf dist && bun build src/index.ts --target=node --outdir dist --splitting --external @earendil-works/pi-coding-agent --banner '#!/usr/bin/env node' && chmod +x dist/index.js",
67
67
  prepublishOnly: "bun run build"
68
68
  },
69
69
  dependencies: {
70
- "@earendil-works/pi-coding-agent": "^0.84.2"
70
+ "@earendil-works/pi-coding-agent": "0.84.4"
71
71
  },
72
72
  devDependencies: {
73
73
  "@freepi/pi-ads": "workspace:*",
@@ -14512,7 +14512,10 @@ var MeResponseSchema = exports_external.object({
14512
14512
  handle: exports_external.string(),
14513
14513
  remaining_usd_today: exports_external.number(),
14514
14514
  cap_usd_today: exports_external.number(),
14515
- tier: AccountTierSchema
14515
+ tier: AccountTierSchema,
14516
+ credit_usd: exports_external.number(),
14517
+ notice: exports_external.string().optional(),
14518
+ buy_url: exports_external.string().optional()
14516
14519
  });
14517
14520
  var MeStatsResponseSchema = exports_external.object({
14518
14521
  user_id: exports_external.string(),
@@ -14521,6 +14524,7 @@ var MeStatsResponseSchema = exports_external.object({
14521
14524
  cap_usd_today: exports_external.number(),
14522
14525
  spent_usd_today: exports_external.number(),
14523
14526
  remaining_usd_today: exports_external.number(),
14527
+ credit_usd: exports_external.number(),
14524
14528
  request_count_today: exports_external.number(),
14525
14529
  prompt_tokens_today: exports_external.number(),
14526
14530
  completion_tokens_today: exports_external.number(),
@@ -14594,6 +14598,8 @@ var ConfigSchema = exports_external.object({
14594
14598
  contextCharBudget: exports_external.number().int().default(800000),
14595
14599
  accountsPerDayCeiling: exports_external.number().int().default(500),
14596
14600
  authRatePerIpPerHour: exports_external.number().int().default(30),
14601
+ tokenRatePerIpPerHour: exports_external.number().int().default(3600),
14602
+ consentRatePerIpPerHour: exports_external.number().int().default(60),
14597
14603
  adInlineTurnFrequency: exports_external.number().int().default(5),
14598
14604
  adMinColumns: exports_external.number().int().default(60),
14599
14605
  proxyBaseUrl: exports_external.string().default("https://api.freepi.ai"),
@@ -14628,7 +14634,8 @@ var ConfigSchema = exports_external.object({
14628
14634
  abuseAdBypassMinRequests: exports_external.number().int().default(20),
14629
14635
  abuseAdBypassRatio: exports_external.number().int().default(10),
14630
14636
  traceMaxInflightWrites: exports_external.number().int().default(32),
14631
- catalogCacheTtlSeconds: exports_external.number().int().default(60)
14637
+ catalogCacheTtlSeconds: exports_external.number().int().default(60),
14638
+ eventMaxInflightWrites: exports_external.number().int().default(128)
14632
14639
  });
14633
14640
  function envNumber(value) {
14634
14641
  if (value === undefined || value === "")
@@ -14656,6 +14663,8 @@ function loadConfig(env = process.env) {
14656
14663
  contextCharBudget: envNumber(env.CONTEXT_CHAR_BUDGET),
14657
14664
  accountsPerDayCeiling: envNumber(env.ACCOUNTS_PER_DAY_CEILING),
14658
14665
  authRatePerIpPerHour: envNumber(env.AUTH_RATE_PER_IP_PER_HOUR),
14666
+ tokenRatePerIpPerHour: envNumber(env.TOKEN_RATE_PER_IP_PER_HOUR),
14667
+ consentRatePerIpPerHour: envNumber(env.CONSENT_RATE_PER_IP_PER_HOUR),
14659
14668
  adInlineTurnFrequency: envNumber(env.AD_INLINE_TURN_FREQUENCY),
14660
14669
  adMinColumns: envNumber(env.AD_MIN_COLUMNS),
14661
14670
  proxyBaseUrl: env.PROXY_BASE_URL || undefined,
@@ -14690,7 +14699,8 @@ function loadConfig(env = process.env) {
14690
14699
  abuseAdBypassMinRequests: envNumber(env.ABUSE_AD_BYPASS_MIN_REQUESTS),
14691
14700
  abuseAdBypassRatio: envNumber(env.ABUSE_AD_BYPASS_RATIO),
14692
14701
  traceMaxInflightWrites: envNumber(env.TRACE_MAX_INFLIGHT_WRITES),
14693
- catalogCacheTtlSeconds: envNumber(env.CATALOG_CACHE_TTL_SECONDS)
14702
+ catalogCacheTtlSeconds: envNumber(env.CATALOG_CACHE_TTL_SECONDS),
14703
+ eventMaxInflightWrites: envNumber(env.EVENT_MAX_INFLIGHT_WRITES)
14694
14704
  });
14695
14705
  }
14696
14706
  // ../shared/src/version.ts
@@ -14916,6 +14926,11 @@ async function renderMeter(deps, ctx) {
14916
14926
  return;
14917
14927
  }
14918
14928
  const theme = ctx.ui.theme;
14929
+ const notice = typeof me.notice === "string" ? sanitizeText(me.notice).trim() : "";
14930
+ if (notice !== "") {
14931
+ ctx.ui.setWidget(METER_WIDGET_ID, [renderErrorLine(notice, theme)]);
14932
+ return;
14933
+ }
14919
14934
  const errorCode = inferErrorFromRemainingBudget(me.remaining_usd_today);
14920
14935
  if (errorCode === undefined) {
14921
14936
  ctx.ui.setWidget(METER_WIDGET_ID, undefined);
@@ -19256,9 +19271,11 @@ __export(exports_typebox, {
19256
19271
  var USAGE_TOOL_NAME = "free_pi_usage";
19257
19272
  var PARAMS = exports_typebox.Object({});
19258
19273
  function formatStats(stats) {
19274
+ const credit = stats.credit_usd;
19259
19275
  return [
19260
19276
  `tier: ${stats.tier} (cap $${stats.cap_usd_today.toFixed(2)}/day)`,
19261
19277
  `today: spent $${stats.spent_usd_today.toFixed(4)}, remaining $${stats.remaining_usd_today.toFixed(4)}, ${stats.request_count_today} request(s)`,
19278
+ ...typeof credit === "number" ? [`credit: $${credit.toFixed(2)} purchased usage remaining`] : [],
19262
19279
  `today tokens: ${stats.prompt_tokens_today} prompt / ${stats.completion_tokens_today} completion`,
19263
19280
  `lifetime: spent $${stats.lifetime.spent_usd.toFixed(4)}, ${stats.lifetime.request_count} request(s), ${stats.lifetime.prompt_tokens} prompt / ${stats.lifetime.completion_tokens} completion tokens`
19264
19281
  ].join(`
@@ -19305,6 +19322,65 @@ function createUsageToolExtension(opts) {
19305
19322
  };
19306
19323
  }
19307
19324
 
19325
+ // src/buy-tool.ts
19326
+ var BUY_TOOL_NAME = "free_pi_buy_credits";
19327
+ var PARAMS2 = exports_typebox.Object({});
19328
+ var NOT_AVAILABLE_TEXT = "Buying credits is not available on this server yet.";
19329
+ function buyText(url2) {
19330
+ return `Opening the buy page in your browser. If it did not open (for example over SSH), visit:
19331
+ ${url2}
19332
+
19333
+ Packs: $5 → $4.00 of usage, $10 → $8.00. Card or USDC.`;
19334
+ }
19335
+ function createBuyToolExtension(opts) {
19336
+ return {
19337
+ name: "free-pi-buy-tool",
19338
+ factory(pi) {
19339
+ pi.registerTool({
19340
+ name: BUY_TOOL_NAME,
19341
+ label: "Buy Credits",
19342
+ description: "Opens the free-pi buy-credits page in your browser (and prints the URL, for SSH sessions with no browser). Read-only against the server, takes no arguments.",
19343
+ promptSnippet: "Buy more free-pi credits",
19344
+ parameters: PARAMS2,
19345
+ async execute() {
19346
+ try {
19347
+ const token = await opts.getToken();
19348
+ const doFetch = opts.fetchImpl ?? fetch;
19349
+ const openBrowserFn = opts.openBrowserImpl ?? openBrowser;
19350
+ const res = await doFetch(`${opts.baseUrl}/me`, {
19351
+ headers: { Authorization: `Bearer ${token}` },
19352
+ signal: AbortSignal.timeout(5000)
19353
+ });
19354
+ if (!res.ok) {
19355
+ return {
19356
+ content: [{ type: "text", text: `Could not fetch the buy page (HTTP ${res.status}).` }],
19357
+ details: { ok: false }
19358
+ };
19359
+ }
19360
+ const me = await res.json();
19361
+ if (!me.buy_url) {
19362
+ return {
19363
+ content: [{ type: "text", text: NOT_AVAILABLE_TEXT }],
19364
+ details: { available: false }
19365
+ };
19366
+ }
19367
+ openBrowserFn(me.buy_url);
19368
+ return {
19369
+ content: [{ type: "text", text: buyText(me.buy_url) }],
19370
+ details: { buy_url: me.buy_url }
19371
+ };
19372
+ } catch (err) {
19373
+ return {
19374
+ content: [{ type: "text", text: `Could not fetch the buy page: ${String(err)}` }],
19375
+ details: { ok: false }
19376
+ };
19377
+ }
19378
+ }
19379
+ });
19380
+ }
19381
+ };
19382
+ }
19383
+
19308
19384
  // src/tool-guard.ts
19309
19385
  async function reportToolGuardTrigger(opts, toolName) {
19310
19386
  try {
@@ -19334,6 +19410,19 @@ function createToolGuardExtension(opts) {
19334
19410
 
19335
19411
  // src/changelog.ts
19336
19412
  var CHANGELOG_HIGHLIGHTS = [
19413
+ {
19414
+ version: "0.2.11",
19415
+ highlights: [
19416
+ 'Out of free usage? You can now buy more — $5 or $10 packs, card or USDC. Ask pi to "buy credits" or follow the link in the out-of-usage notice.',
19417
+ "The out-of-usage notice now comes from the server, and `free_pi_usage` shows your purchased balance."
19418
+ ]
19419
+ },
19420
+ {
19421
+ version: "0.2.10",
19422
+ highlights: [
19423
+ "free-pi now installs an exact, tested version of the underlying agent — an upstream release can no longer change your CLI without us testing it first."
19424
+ ]
19425
+ },
19337
19426
  {
19338
19427
  version: "0.2.9",
19339
19428
  highlights: [
@@ -19479,7 +19568,7 @@ function catalogModelsFor(opts) {
19479
19568
  const id = opts.model || MODEL_ID;
19480
19569
  return [{ id, name: id }];
19481
19570
  }
19482
- var ALLOWED_TOOL_NAMES = [...SAFE_TOOLS, USAGE_TOOL_NAME];
19571
+ var ALLOWED_TOOL_NAMES = [...SAFE_TOOLS, USAGE_TOOL_NAME, BUY_TOOL_NAME];
19483
19572
  function buildRuntimeOptions(opts, sessionId) {
19484
19573
  const models = catalogModelsFor(opts);
19485
19574
  const providerExtension = {
@@ -19497,6 +19586,10 @@ function buildRuntimeOptions(opts, sessionId) {
19497
19586
  baseUrl: opts.baseUrl,
19498
19587
  getToken: () => opts.jwt
19499
19588
  });
19589
+ const buyToolExtension = createBuyToolExtension({
19590
+ baseUrl: opts.baseUrl,
19591
+ getToken: () => opts.jwt
19592
+ });
19500
19593
  const toolGuardExtension = createToolGuardExtension({
19501
19594
  baseUrl: opts.baseUrl,
19502
19595
  getToken: () => opts.jwt,
@@ -19510,6 +19603,7 @@ function buildRuntimeOptions(opts, sessionId) {
19510
19603
  providerExtension,
19511
19604
  adsExtension,
19512
19605
  usageToolExtension,
19606
+ buyToolExtension,
19513
19607
  toolGuardExtension,
19514
19608
  commandsExtension
19515
19609
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
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",
@@ -15,11 +15,11 @@
15
15
  "node": ">=22.19.0"
16
16
  },
17
17
  "scripts": {
18
- "build": "bun build src/index.ts --target=node --outdir dist --splitting --external @earendil-works/pi-coding-agent --banner '#!/usr/bin/env node' && chmod +x dist/index.js",
18
+ "build": "rm -rf dist && bun build src/index.ts --target=node --outdir dist --splitting --external @earendil-works/pi-coding-agent --banner '#!/usr/bin/env node' && chmod +x dist/index.js",
19
19
  "prepublishOnly": "bun run build"
20
20
  },
21
21
  "dependencies": {
22
- "@earendil-works/pi-coding-agent": "^0.84.2"
22
+ "@earendil-works/pi-coding-agent": "0.84.4"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@freepi/pi-ads": "workspace:*",