free-pi-cli 0.2.11 → 0.2.13
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-q2v4gzhd.js → main-e58f4t8x.js} +171 -67
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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.
|
|
51
|
+
version: "0.2.13",
|
|
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",
|
|
@@ -14525,6 +14525,7 @@ var MeStatsResponseSchema = exports_external.object({
|
|
|
14525
14525
|
spent_usd_today: exports_external.number(),
|
|
14526
14526
|
remaining_usd_today: exports_external.number(),
|
|
14527
14527
|
credit_usd: exports_external.number(),
|
|
14528
|
+
credit_credits: exports_external.number(),
|
|
14528
14529
|
request_count_today: exports_external.number(),
|
|
14529
14530
|
prompt_tokens_today: exports_external.number(),
|
|
14530
14531
|
completion_tokens_today: exports_external.number(),
|
|
@@ -14591,7 +14592,7 @@ function assertExhaustiveErrorCode(code) {
|
|
|
14591
14592
|
}
|
|
14592
14593
|
// ../shared/src/config.ts
|
|
14593
14594
|
var ConfigSchema = exports_external.object({
|
|
14594
|
-
perUserDailyCapUsd: exports_external.number().default(5),
|
|
14595
|
+
perUserDailyCapUsd: exports_external.number().default(2.5),
|
|
14595
14596
|
perUserRollingCapUsd: exports_external.number().default(0),
|
|
14596
14597
|
rollingCapWindowHours: exports_external.number().int().default(5),
|
|
14597
14598
|
globalDailyCapUsd: exports_external.number().default(50),
|
|
@@ -14719,6 +14720,11 @@ function compareVersions(a, b) {
|
|
|
14719
14720
|
}
|
|
14720
14721
|
return 0;
|
|
14721
14722
|
}
|
|
14723
|
+
// ../shared/src/credits.ts
|
|
14724
|
+
var CREDITS_PER_USD = 40000 / 3;
|
|
14725
|
+
function usdToCredits(usd) {
|
|
14726
|
+
return Math.round(Number(usd) * CREDITS_PER_USD);
|
|
14727
|
+
}
|
|
14722
14728
|
// ../pi-ads/src/api.ts
|
|
14723
14729
|
var REQUEST_TIMEOUT_MS = 3000;
|
|
14724
14730
|
async function authedFetch(deps, path, init) {
|
|
@@ -14919,6 +14925,12 @@ function inferErrorFromRemainingBudget(remainingUsdToday) {
|
|
|
14919
14925
|
|
|
14920
14926
|
// ../pi-ads/src/meter.ts
|
|
14921
14927
|
var METER_WIDGET_ID = "freepi-meter";
|
|
14928
|
+
var CONFIRM_TURNS = 3;
|
|
14929
|
+
var lastCreditUsd;
|
|
14930
|
+
var confirm;
|
|
14931
|
+
function creditAddedMessage(addedUsd) {
|
|
14932
|
+
return `Payment received — ${usdToCredits(addedUsd).toLocaleString("en-US")} credits added to your balance.`;
|
|
14933
|
+
}
|
|
14922
14934
|
async function renderMeter(deps, ctx) {
|
|
14923
14935
|
const me = await fetchMe(deps);
|
|
14924
14936
|
if (!me) {
|
|
@@ -14926,6 +14938,17 @@ async function renderMeter(deps, ctx) {
|
|
|
14926
14938
|
return;
|
|
14927
14939
|
}
|
|
14928
14940
|
const theme = ctx.ui.theme;
|
|
14941
|
+
const credit = typeof me.credit_usd === "number" ? me.credit_usd : undefined;
|
|
14942
|
+
const added = credit !== undefined && lastCreditUsd !== undefined ? credit - lastCreditUsd : 0;
|
|
14943
|
+
lastCreditUsd = credit;
|
|
14944
|
+
if (added > 0)
|
|
14945
|
+
confirm = { addedUsd: added, turnsLeft: CONFIRM_TURNS };
|
|
14946
|
+
if (confirm && confirm.turnsLeft > 0) {
|
|
14947
|
+
confirm.turnsLeft--;
|
|
14948
|
+
ctx.ui.setWidget(METER_WIDGET_ID, [renderErrorLine(creditAddedMessage(confirm.addedUsd), theme)]);
|
|
14949
|
+
return;
|
|
14950
|
+
}
|
|
14951
|
+
confirm = undefined;
|
|
14929
14952
|
const notice = typeof me.notice === "string" ? sanitizeText(me.notice).trim() : "";
|
|
14930
14953
|
if (notice !== "") {
|
|
14931
14954
|
ctx.ui.setWidget(METER_WIDGET_ID, [renderErrorLine(notice, theme)]);
|
|
@@ -19270,17 +19293,38 @@ __export(exports_typebox, {
|
|
|
19270
19293
|
// src/usage-tool.ts
|
|
19271
19294
|
var USAGE_TOOL_NAME = "free_pi_usage";
|
|
19272
19295
|
var PARAMS = exports_typebox.Object({});
|
|
19296
|
+
function percentUsed(spentUsd, capUsd) {
|
|
19297
|
+
if (!(capUsd > 0))
|
|
19298
|
+
return 100;
|
|
19299
|
+
return Math.min(100, Math.max(0, Math.round(spentUsd / capUsd * 100)));
|
|
19300
|
+
}
|
|
19273
19301
|
function formatStats(stats) {
|
|
19274
|
-
const
|
|
19302
|
+
const credits2 = stats.credit_credits;
|
|
19275
19303
|
return [
|
|
19276
|
-
`tier: ${stats.tier}
|
|
19277
|
-
`today:
|
|
19278
|
-
...typeof
|
|
19304
|
+
`tier: ${stats.tier}`,
|
|
19305
|
+
`today: ${percentUsed(stats.spent_usd_today, stats.cap_usd_today)}% of your free daily allowance used`,
|
|
19306
|
+
...typeof credits2 === "number" ? [`credit: ${credits2.toLocaleString("en-US")} credits remaining`] : [],
|
|
19279
19307
|
`today tokens: ${stats.prompt_tokens_today} prompt / ${stats.completion_tokens_today} completion`,
|
|
19280
|
-
`lifetime:
|
|
19308
|
+
`lifetime: ${stats.lifetime.prompt_tokens} prompt / ${stats.lifetime.completion_tokens} completion tokens`
|
|
19281
19309
|
].join(`
|
|
19282
19310
|
`);
|
|
19283
19311
|
}
|
|
19312
|
+
async function fetchUsageText(opts) {
|
|
19313
|
+
try {
|
|
19314
|
+
const token = await opts.getToken();
|
|
19315
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
19316
|
+
const res = await doFetch(`${opts.baseUrl}/me/stats`, {
|
|
19317
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
19318
|
+
signal: AbortSignal.timeout(5000)
|
|
19319
|
+
});
|
|
19320
|
+
if (!res.ok)
|
|
19321
|
+
return { ok: false, text: `Could not fetch usage (HTTP ${res.status}).` };
|
|
19322
|
+
const stats = await res.json();
|
|
19323
|
+
return { ok: true, text: formatStats(stats), stats };
|
|
19324
|
+
} catch (err) {
|
|
19325
|
+
return { ok: false, text: `Could not fetch usage: ${String(err)}` };
|
|
19326
|
+
}
|
|
19327
|
+
}
|
|
19284
19328
|
function createUsageToolExtension(opts) {
|
|
19285
19329
|
return {
|
|
19286
19330
|
name: "free-pi-usage-tool",
|
|
@@ -19288,34 +19332,15 @@ function createUsageToolExtension(opts) {
|
|
|
19288
19332
|
pi.registerTool({
|
|
19289
19333
|
name: USAGE_TOOL_NAME,
|
|
19290
19334
|
label: "My Usage",
|
|
19291
|
-
description: "Reports the caller's
|
|
19292
|
-
promptSnippet: "Check your own free-pi usage
|
|
19335
|
+
description: "Reports how much of the caller's free daily allowance is used (as a percentage), purchased credit, token counts, and account tier. Read-only, takes no arguments, makes no changes.",
|
|
19336
|
+
promptSnippet: "Check your own free-pi usage and remaining daily allowance",
|
|
19293
19337
|
parameters: PARAMS,
|
|
19294
19338
|
async execute() {
|
|
19295
|
-
|
|
19296
|
-
|
|
19297
|
-
|
|
19298
|
-
|
|
19299
|
-
|
|
19300
|
-
signal: AbortSignal.timeout(5000)
|
|
19301
|
-
});
|
|
19302
|
-
if (!res.ok) {
|
|
19303
|
-
return {
|
|
19304
|
-
content: [{ type: "text", text: `Could not fetch usage (HTTP ${res.status}).` }],
|
|
19305
|
-
details: { ok: false }
|
|
19306
|
-
};
|
|
19307
|
-
}
|
|
19308
|
-
const stats = await res.json();
|
|
19309
|
-
return {
|
|
19310
|
-
content: [{ type: "text", text: formatStats(stats) }],
|
|
19311
|
-
details: stats
|
|
19312
|
-
};
|
|
19313
|
-
} catch (err) {
|
|
19314
|
-
return {
|
|
19315
|
-
content: [{ type: "text", text: `Could not fetch usage: ${String(err)}` }],
|
|
19316
|
-
details: { ok: false }
|
|
19317
|
-
};
|
|
19318
|
-
}
|
|
19339
|
+
const r = await fetchUsageText(opts);
|
|
19340
|
+
return {
|
|
19341
|
+
content: [{ type: "text", text: r.text }],
|
|
19342
|
+
details: r.ok ? r.stats : { ok: false }
|
|
19343
|
+
};
|
|
19319
19344
|
}
|
|
19320
19345
|
});
|
|
19321
19346
|
}
|
|
@@ -19323,15 +19348,31 @@ function createUsageToolExtension(opts) {
|
|
|
19323
19348
|
}
|
|
19324
19349
|
|
|
19325
19350
|
// src/buy-tool.ts
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19351
|
+
async function resolveBuyPage(opts) {
|
|
19352
|
+
try {
|
|
19353
|
+
const token = await opts.getToken();
|
|
19354
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
19355
|
+
const res = await doFetch(`${opts.baseUrl}/me`, {
|
|
19356
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
19357
|
+
signal: AbortSignal.timeout(5000)
|
|
19358
|
+
});
|
|
19359
|
+
if (!res.ok)
|
|
19360
|
+
return { kind: "error", text: `Could not fetch the buy page (HTTP ${res.status}).` };
|
|
19361
|
+
const me = await res.json();
|
|
19362
|
+
return me.buy_url ? { kind: "url", url: me.buy_url } : { kind: "unavailable" };
|
|
19363
|
+
} catch (err) {
|
|
19364
|
+
return { kind: "error", text: `Could not fetch the buy page: ${String(err)}` };
|
|
19365
|
+
}
|
|
19366
|
+
}
|
|
19367
|
+
var BUY_NOT_AVAILABLE_TEXT = "Buying credits is not available on this server yet.";
|
|
19368
|
+
function buyPageText(url2) {
|
|
19330
19369
|
return `Opening the buy page in your browser. If it did not open (for example over SSH), visit:
|
|
19331
19370
|
${url2}
|
|
19332
19371
|
|
|
19333
|
-
Packs: $5 →
|
|
19372
|
+
Packs: $5 → 50,000 credits, $10 → 100,000 credits. Card or USDC.`;
|
|
19334
19373
|
}
|
|
19374
|
+
var BUY_TOOL_NAME = "free_pi_buy_credits";
|
|
19375
|
+
var PARAMS2 = exports_typebox.Object({});
|
|
19335
19376
|
function createBuyToolExtension(opts) {
|
|
19336
19377
|
return {
|
|
19337
19378
|
name: "free-pi-buy-tool",
|
|
@@ -19343,44 +19384,69 @@ function createBuyToolExtension(opts) {
|
|
|
19343
19384
|
promptSnippet: "Buy more free-pi credits",
|
|
19344
19385
|
parameters: PARAMS2,
|
|
19345
19386
|
async execute() {
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19349
|
-
|
|
19350
|
-
|
|
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) {
|
|
19387
|
+
const page = await resolveBuyPage(opts);
|
|
19388
|
+
if (page.kind === "error") {
|
|
19389
|
+
return { content: [{ type: "text", text: page.text }], details: { ok: false } };
|
|
19390
|
+
}
|
|
19391
|
+
if (page.kind === "unavailable") {
|
|
19373
19392
|
return {
|
|
19374
|
-
content: [{ type: "text", text:
|
|
19375
|
-
details: {
|
|
19393
|
+
content: [{ type: "text", text: BUY_NOT_AVAILABLE_TEXT }],
|
|
19394
|
+
details: { available: false }
|
|
19376
19395
|
};
|
|
19377
19396
|
}
|
|
19397
|
+
(opts.openBrowserImpl ?? openBrowser)(page.url);
|
|
19398
|
+
return {
|
|
19399
|
+
content: [{ type: "text", text: buyPageText(page.url) }],
|
|
19400
|
+
details: { buy_url: page.url }
|
|
19401
|
+
};
|
|
19378
19402
|
}
|
|
19379
19403
|
});
|
|
19380
19404
|
}
|
|
19381
19405
|
};
|
|
19382
19406
|
}
|
|
19383
19407
|
|
|
19408
|
+
// src/error-notice.ts
|
|
19409
|
+
var NOTICE_DEDUPE_MS = 15000;
|
|
19410
|
+
function parseErrorEnvelope(errorMessage) {
|
|
19411
|
+
if (typeof errorMessage !== "string")
|
|
19412
|
+
return;
|
|
19413
|
+
const m = /^(\d{3}): (\{[\s\S]*\})\s*$/.exec(errorMessage);
|
|
19414
|
+
if (!m)
|
|
19415
|
+
return;
|
|
19416
|
+
try {
|
|
19417
|
+
const body = JSON.parse(m[2]);
|
|
19418
|
+
const message = body.message ?? body.error?.message;
|
|
19419
|
+
const code = body.code ?? body.error?.code;
|
|
19420
|
+
if (typeof message !== "string" || message.trim() === "")
|
|
19421
|
+
return;
|
|
19422
|
+
return { status: Number(m[1]), code: typeof code === "string" ? code : "unknown", message };
|
|
19423
|
+
} catch {
|
|
19424
|
+
return;
|
|
19425
|
+
}
|
|
19426
|
+
}
|
|
19427
|
+
function createErrorNoticeExtension(opts = {}) {
|
|
19428
|
+
const lastAt = new Map;
|
|
19429
|
+
const now = opts.now ?? Date.now;
|
|
19430
|
+
return {
|
|
19431
|
+
name: "free-pi-error-notice",
|
|
19432
|
+
factory(pi) {
|
|
19433
|
+
pi.on("turn_end", (event, ctx) => {
|
|
19434
|
+
const msg = event.message;
|
|
19435
|
+
if (!msg || msg.stopReason !== "error")
|
|
19436
|
+
return;
|
|
19437
|
+
const env = parseErrorEnvelope(msg.errorMessage);
|
|
19438
|
+
if (!env)
|
|
19439
|
+
return;
|
|
19440
|
+
const t = now();
|
|
19441
|
+
if (t - (lastAt.get(env.code) ?? -Infinity) < NOTICE_DEDUPE_MS)
|
|
19442
|
+
return;
|
|
19443
|
+
lastAt.set(env.code, t);
|
|
19444
|
+
ctx.ui.notify(env.message, env.status >= 500 ? "error" : "warning");
|
|
19445
|
+
});
|
|
19446
|
+
}
|
|
19447
|
+
};
|
|
19448
|
+
}
|
|
19449
|
+
|
|
19384
19450
|
// src/tool-guard.ts
|
|
19385
19451
|
async function reportToolGuardTrigger(opts, toolName) {
|
|
19386
19452
|
try {
|
|
@@ -19410,6 +19476,21 @@ function createToolGuardExtension(opts) {
|
|
|
19410
19476
|
|
|
19411
19477
|
// src/changelog.ts
|
|
19412
19478
|
var CHANGELOG_HIGHLIGHTS = [
|
|
19479
|
+
{
|
|
19480
|
+
version: "0.2.13",
|
|
19481
|
+
highlights: [
|
|
19482
|
+
"Purchased balance is now shown as credits — $5 buys 50,000 credits, $10 buys 100,000.",
|
|
19483
|
+
"The usage summary is cleaner: your free allowance still shows as a percentage, with token counts, and no request tally."
|
|
19484
|
+
]
|
|
19485
|
+
},
|
|
19486
|
+
{
|
|
19487
|
+
version: "0.2.12",
|
|
19488
|
+
highlights: [
|
|
19489
|
+
"New: /buy-credits and /usage slash commands — work instantly, even when you are out of usage.",
|
|
19490
|
+
"Free usage is shown as a percentage, never a dollar figure; purchased credit stays in dollars.",
|
|
19491
|
+
"Clearer messages: one readable line when a request is rejected, a heads-up at 80% of your daily allowance, and a confirmation when a purchase lands."
|
|
19492
|
+
]
|
|
19493
|
+
},
|
|
19413
19494
|
{
|
|
19414
19495
|
version: "0.2.11",
|
|
19415
19496
|
highlights: [
|
|
@@ -19528,6 +19609,19 @@ async function runUpdate(ctx, deps = {}) {
|
|
|
19528
19609
|
ctx.ui.notify("Update failed. Try manually: npm install -g free-pi-cli@latest", "error");
|
|
19529
19610
|
}
|
|
19530
19611
|
}
|
|
19612
|
+
async function buyCredits(opts, ctx) {
|
|
19613
|
+
const page = await resolveBuyPage(opts);
|
|
19614
|
+
if (page.kind === "error")
|
|
19615
|
+
return ctx.ui.notify(page.text, "error");
|
|
19616
|
+
if (page.kind === "unavailable")
|
|
19617
|
+
return ctx.ui.notify(BUY_NOT_AVAILABLE_TEXT, "info");
|
|
19618
|
+
(opts.openBrowserImpl ?? openBrowser)(page.url);
|
|
19619
|
+
ctx.ui.notify(buyPageText(page.url), "info");
|
|
19620
|
+
}
|
|
19621
|
+
async function showUsage(opts, ctx) {
|
|
19622
|
+
const r = await fetchUsageText(opts);
|
|
19623
|
+
ctx.ui.notify(r.text, r.ok ? "info" : "error");
|
|
19624
|
+
}
|
|
19531
19625
|
function createFreePiCommandsExtension(opts) {
|
|
19532
19626
|
return {
|
|
19533
19627
|
name: "free-pi-commands",
|
|
@@ -19544,6 +19638,14 @@ function createFreePiCommandsExtension(opts) {
|
|
|
19544
19638
|
description: "Update free-pi-cli to the latest version.",
|
|
19545
19639
|
handler: (_args, ctx) => runUpdate(ctx)
|
|
19546
19640
|
});
|
|
19641
|
+
pi.registerCommand("usage", {
|
|
19642
|
+
description: "Show how much of today's free allowance you have used, and your purchased credit.",
|
|
19643
|
+
handler: (_args, ctx) => showUsage(opts, ctx)
|
|
19644
|
+
});
|
|
19645
|
+
pi.registerCommand("buy-credits", {
|
|
19646
|
+
description: "Buy more usage ($5 or $10 packs, card or USDC) — opens the buy page.",
|
|
19647
|
+
handler: (_args, ctx) => buyCredits(opts, ctx)
|
|
19648
|
+
});
|
|
19547
19649
|
}
|
|
19548
19650
|
};
|
|
19549
19651
|
}
|
|
@@ -19590,6 +19692,7 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
19590
19692
|
baseUrl: opts.baseUrl,
|
|
19591
19693
|
getToken: () => opts.jwt
|
|
19592
19694
|
});
|
|
19695
|
+
const errorNoticeExtension = createErrorNoticeExtension();
|
|
19593
19696
|
const toolGuardExtension = createToolGuardExtension({
|
|
19594
19697
|
baseUrl: opts.baseUrl,
|
|
19595
19698
|
getToken: () => opts.jwt,
|
|
@@ -19604,6 +19707,7 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
19604
19707
|
adsExtension,
|
|
19605
19708
|
usageToolExtension,
|
|
19606
19709
|
buyToolExtension,
|
|
19710
|
+
errorNoticeExtension,
|
|
19607
19711
|
toolGuardExtension,
|
|
19608
19712
|
commandsExtension
|
|
19609
19713
|
];
|