free-pi-cli 0.2.11 → 0.2.12
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-mh0wmxjc.js} +154 -63
- 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.12",
|
|
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",
|
|
@@ -14919,6 +14919,12 @@ function inferErrorFromRemainingBudget(remainingUsdToday) {
|
|
|
14919
14919
|
|
|
14920
14920
|
// ../pi-ads/src/meter.ts
|
|
14921
14921
|
var METER_WIDGET_ID = "freepi-meter";
|
|
14922
|
+
var CONFIRM_TURNS = 3;
|
|
14923
|
+
var lastCreditUsd;
|
|
14924
|
+
var confirm;
|
|
14925
|
+
function creditAddedMessage(addedUsd) {
|
|
14926
|
+
return `Payment received — $${addedUsd.toFixed(2)} of usage added to your balance.`;
|
|
14927
|
+
}
|
|
14922
14928
|
async function renderMeter(deps, ctx) {
|
|
14923
14929
|
const me = await fetchMe(deps);
|
|
14924
14930
|
if (!me) {
|
|
@@ -14926,6 +14932,17 @@ async function renderMeter(deps, ctx) {
|
|
|
14926
14932
|
return;
|
|
14927
14933
|
}
|
|
14928
14934
|
const theme = ctx.ui.theme;
|
|
14935
|
+
const credit = typeof me.credit_usd === "number" ? me.credit_usd : undefined;
|
|
14936
|
+
const added = credit !== undefined && lastCreditUsd !== undefined ? credit - lastCreditUsd : 0;
|
|
14937
|
+
lastCreditUsd = credit;
|
|
14938
|
+
if (added > 0)
|
|
14939
|
+
confirm = { addedUsd: added, turnsLeft: CONFIRM_TURNS };
|
|
14940
|
+
if (confirm && confirm.turnsLeft > 0) {
|
|
14941
|
+
confirm.turnsLeft--;
|
|
14942
|
+
ctx.ui.setWidget(METER_WIDGET_ID, [renderErrorLine(creditAddedMessage(confirm.addedUsd), theme)]);
|
|
14943
|
+
return;
|
|
14944
|
+
}
|
|
14945
|
+
confirm = undefined;
|
|
14929
14946
|
const notice = typeof me.notice === "string" ? sanitizeText(me.notice).trim() : "";
|
|
14930
14947
|
if (notice !== "") {
|
|
14931
14948
|
ctx.ui.setWidget(METER_WIDGET_ID, [renderErrorLine(notice, theme)]);
|
|
@@ -19270,17 +19287,38 @@ __export(exports_typebox, {
|
|
|
19270
19287
|
// src/usage-tool.ts
|
|
19271
19288
|
var USAGE_TOOL_NAME = "free_pi_usage";
|
|
19272
19289
|
var PARAMS = exports_typebox.Object({});
|
|
19290
|
+
function percentUsed(spentUsd, capUsd) {
|
|
19291
|
+
if (!(capUsd > 0))
|
|
19292
|
+
return 100;
|
|
19293
|
+
return Math.min(100, Math.max(0, Math.round(spentUsd / capUsd * 100)));
|
|
19294
|
+
}
|
|
19273
19295
|
function formatStats(stats) {
|
|
19274
19296
|
const credit = stats.credit_usd;
|
|
19275
19297
|
return [
|
|
19276
|
-
`tier: ${stats.tier}
|
|
19277
|
-
`today:
|
|
19298
|
+
`tier: ${stats.tier}`,
|
|
19299
|
+
`today: ${percentUsed(stats.spent_usd_today, stats.cap_usd_today)}% of your free daily allowance used, ${stats.request_count_today} request(s)`,
|
|
19278
19300
|
...typeof credit === "number" ? [`credit: $${credit.toFixed(2)} purchased usage remaining`] : [],
|
|
19279
19301
|
`today tokens: ${stats.prompt_tokens_today} prompt / ${stats.completion_tokens_today} completion`,
|
|
19280
|
-
`lifetime:
|
|
19302
|
+
`lifetime: ${stats.lifetime.request_count} request(s), ${stats.lifetime.prompt_tokens} prompt / ${stats.lifetime.completion_tokens} completion tokens`
|
|
19281
19303
|
].join(`
|
|
19282
19304
|
`);
|
|
19283
19305
|
}
|
|
19306
|
+
async function fetchUsageText(opts) {
|
|
19307
|
+
try {
|
|
19308
|
+
const token = await opts.getToken();
|
|
19309
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
19310
|
+
const res = await doFetch(`${opts.baseUrl}/me/stats`, {
|
|
19311
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
19312
|
+
signal: AbortSignal.timeout(5000)
|
|
19313
|
+
});
|
|
19314
|
+
if (!res.ok)
|
|
19315
|
+
return { ok: false, text: `Could not fetch usage (HTTP ${res.status}).` };
|
|
19316
|
+
const stats = await res.json();
|
|
19317
|
+
return { ok: true, text: formatStats(stats), stats };
|
|
19318
|
+
} catch (err) {
|
|
19319
|
+
return { ok: false, text: `Could not fetch usage: ${String(err)}` };
|
|
19320
|
+
}
|
|
19321
|
+
}
|
|
19284
19322
|
function createUsageToolExtension(opts) {
|
|
19285
19323
|
return {
|
|
19286
19324
|
name: "free-pi-usage-tool",
|
|
@@ -19288,34 +19326,15 @@ function createUsageToolExtension(opts) {
|
|
|
19288
19326
|
pi.registerTool({
|
|
19289
19327
|
name: USAGE_TOOL_NAME,
|
|
19290
19328
|
label: "My Usage",
|
|
19291
|
-
description: "Reports the caller's
|
|
19292
|
-
promptSnippet: "Check your own free-pi usage
|
|
19329
|
+
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.",
|
|
19330
|
+
promptSnippet: "Check your own free-pi usage and remaining daily allowance",
|
|
19293
19331
|
parameters: PARAMS,
|
|
19294
19332
|
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
|
-
}
|
|
19333
|
+
const r = await fetchUsageText(opts);
|
|
19334
|
+
return {
|
|
19335
|
+
content: [{ type: "text", text: r.text }],
|
|
19336
|
+
details: r.ok ? r.stats : { ok: false }
|
|
19337
|
+
};
|
|
19319
19338
|
}
|
|
19320
19339
|
});
|
|
19321
19340
|
}
|
|
@@ -19323,15 +19342,31 @@ function createUsageToolExtension(opts) {
|
|
|
19323
19342
|
}
|
|
19324
19343
|
|
|
19325
19344
|
// src/buy-tool.ts
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19345
|
+
async function resolveBuyPage(opts) {
|
|
19346
|
+
try {
|
|
19347
|
+
const token = await opts.getToken();
|
|
19348
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
19349
|
+
const res = await doFetch(`${opts.baseUrl}/me`, {
|
|
19350
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
19351
|
+
signal: AbortSignal.timeout(5000)
|
|
19352
|
+
});
|
|
19353
|
+
if (!res.ok)
|
|
19354
|
+
return { kind: "error", text: `Could not fetch the buy page (HTTP ${res.status}).` };
|
|
19355
|
+
const me = await res.json();
|
|
19356
|
+
return me.buy_url ? { kind: "url", url: me.buy_url } : { kind: "unavailable" };
|
|
19357
|
+
} catch (err) {
|
|
19358
|
+
return { kind: "error", text: `Could not fetch the buy page: ${String(err)}` };
|
|
19359
|
+
}
|
|
19360
|
+
}
|
|
19361
|
+
var BUY_NOT_AVAILABLE_TEXT = "Buying credits is not available on this server yet.";
|
|
19362
|
+
function buyPageText(url2) {
|
|
19330
19363
|
return `Opening the buy page in your browser. If it did not open (for example over SSH), visit:
|
|
19331
19364
|
${url2}
|
|
19332
19365
|
|
|
19333
19366
|
Packs: $5 → $4.00 of usage, $10 → $8.00. Card or USDC.`;
|
|
19334
19367
|
}
|
|
19368
|
+
var BUY_TOOL_NAME = "free_pi_buy_credits";
|
|
19369
|
+
var PARAMS2 = exports_typebox.Object({});
|
|
19335
19370
|
function createBuyToolExtension(opts) {
|
|
19336
19371
|
return {
|
|
19337
19372
|
name: "free-pi-buy-tool",
|
|
@@ -19343,44 +19378,69 @@ function createBuyToolExtension(opts) {
|
|
|
19343
19378
|
promptSnippet: "Buy more free-pi credits",
|
|
19344
19379
|
parameters: PARAMS2,
|
|
19345
19380
|
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) {
|
|
19381
|
+
const page = await resolveBuyPage(opts);
|
|
19382
|
+
if (page.kind === "error") {
|
|
19383
|
+
return { content: [{ type: "text", text: page.text }], details: { ok: false } };
|
|
19384
|
+
}
|
|
19385
|
+
if (page.kind === "unavailable") {
|
|
19373
19386
|
return {
|
|
19374
|
-
content: [{ type: "text", text:
|
|
19375
|
-
details: {
|
|
19387
|
+
content: [{ type: "text", text: BUY_NOT_AVAILABLE_TEXT }],
|
|
19388
|
+
details: { available: false }
|
|
19376
19389
|
};
|
|
19377
19390
|
}
|
|
19391
|
+
(opts.openBrowserImpl ?? openBrowser)(page.url);
|
|
19392
|
+
return {
|
|
19393
|
+
content: [{ type: "text", text: buyPageText(page.url) }],
|
|
19394
|
+
details: { buy_url: page.url }
|
|
19395
|
+
};
|
|
19378
19396
|
}
|
|
19379
19397
|
});
|
|
19380
19398
|
}
|
|
19381
19399
|
};
|
|
19382
19400
|
}
|
|
19383
19401
|
|
|
19402
|
+
// src/error-notice.ts
|
|
19403
|
+
var NOTICE_DEDUPE_MS = 15000;
|
|
19404
|
+
function parseErrorEnvelope(errorMessage) {
|
|
19405
|
+
if (typeof errorMessage !== "string")
|
|
19406
|
+
return;
|
|
19407
|
+
const m = /^(\d{3}): (\{[\s\S]*\})\s*$/.exec(errorMessage);
|
|
19408
|
+
if (!m)
|
|
19409
|
+
return;
|
|
19410
|
+
try {
|
|
19411
|
+
const body = JSON.parse(m[2]);
|
|
19412
|
+
const message = body.message ?? body.error?.message;
|
|
19413
|
+
const code = body.code ?? body.error?.code;
|
|
19414
|
+
if (typeof message !== "string" || message.trim() === "")
|
|
19415
|
+
return;
|
|
19416
|
+
return { status: Number(m[1]), code: typeof code === "string" ? code : "unknown", message };
|
|
19417
|
+
} catch {
|
|
19418
|
+
return;
|
|
19419
|
+
}
|
|
19420
|
+
}
|
|
19421
|
+
function createErrorNoticeExtension(opts = {}) {
|
|
19422
|
+
const lastAt = new Map;
|
|
19423
|
+
const now = opts.now ?? Date.now;
|
|
19424
|
+
return {
|
|
19425
|
+
name: "free-pi-error-notice",
|
|
19426
|
+
factory(pi) {
|
|
19427
|
+
pi.on("turn_end", (event, ctx) => {
|
|
19428
|
+
const msg = event.message;
|
|
19429
|
+
if (!msg || msg.stopReason !== "error")
|
|
19430
|
+
return;
|
|
19431
|
+
const env = parseErrorEnvelope(msg.errorMessage);
|
|
19432
|
+
if (!env)
|
|
19433
|
+
return;
|
|
19434
|
+
const t = now();
|
|
19435
|
+
if (t - (lastAt.get(env.code) ?? -Infinity) < NOTICE_DEDUPE_MS)
|
|
19436
|
+
return;
|
|
19437
|
+
lastAt.set(env.code, t);
|
|
19438
|
+
ctx.ui.notify(env.message, env.status >= 500 ? "error" : "warning");
|
|
19439
|
+
});
|
|
19440
|
+
}
|
|
19441
|
+
};
|
|
19442
|
+
}
|
|
19443
|
+
|
|
19384
19444
|
// src/tool-guard.ts
|
|
19385
19445
|
async function reportToolGuardTrigger(opts, toolName) {
|
|
19386
19446
|
try {
|
|
@@ -19410,6 +19470,14 @@ function createToolGuardExtension(opts) {
|
|
|
19410
19470
|
|
|
19411
19471
|
// src/changelog.ts
|
|
19412
19472
|
var CHANGELOG_HIGHLIGHTS = [
|
|
19473
|
+
{
|
|
19474
|
+
version: "0.2.12",
|
|
19475
|
+
highlights: [
|
|
19476
|
+
"New: /buy-credits and /usage slash commands — work instantly, even when you are out of usage.",
|
|
19477
|
+
"Free usage is shown as a percentage, never a dollar figure; purchased credit stays in dollars.",
|
|
19478
|
+
"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."
|
|
19479
|
+
]
|
|
19480
|
+
},
|
|
19413
19481
|
{
|
|
19414
19482
|
version: "0.2.11",
|
|
19415
19483
|
highlights: [
|
|
@@ -19528,6 +19596,19 @@ async function runUpdate(ctx, deps = {}) {
|
|
|
19528
19596
|
ctx.ui.notify("Update failed. Try manually: npm install -g free-pi-cli@latest", "error");
|
|
19529
19597
|
}
|
|
19530
19598
|
}
|
|
19599
|
+
async function buyCredits(opts, ctx) {
|
|
19600
|
+
const page = await resolveBuyPage(opts);
|
|
19601
|
+
if (page.kind === "error")
|
|
19602
|
+
return ctx.ui.notify(page.text, "error");
|
|
19603
|
+
if (page.kind === "unavailable")
|
|
19604
|
+
return ctx.ui.notify(BUY_NOT_AVAILABLE_TEXT, "info");
|
|
19605
|
+
(opts.openBrowserImpl ?? openBrowser)(page.url);
|
|
19606
|
+
ctx.ui.notify(buyPageText(page.url), "info");
|
|
19607
|
+
}
|
|
19608
|
+
async function showUsage(opts, ctx) {
|
|
19609
|
+
const r = await fetchUsageText(opts);
|
|
19610
|
+
ctx.ui.notify(r.text, r.ok ? "info" : "error");
|
|
19611
|
+
}
|
|
19531
19612
|
function createFreePiCommandsExtension(opts) {
|
|
19532
19613
|
return {
|
|
19533
19614
|
name: "free-pi-commands",
|
|
@@ -19544,6 +19625,14 @@ function createFreePiCommandsExtension(opts) {
|
|
|
19544
19625
|
description: "Update free-pi-cli to the latest version.",
|
|
19545
19626
|
handler: (_args, ctx) => runUpdate(ctx)
|
|
19546
19627
|
});
|
|
19628
|
+
pi.registerCommand("usage", {
|
|
19629
|
+
description: "Show how much of today's free allowance you have used, and your purchased credit.",
|
|
19630
|
+
handler: (_args, ctx) => showUsage(opts, ctx)
|
|
19631
|
+
});
|
|
19632
|
+
pi.registerCommand("buy-credits", {
|
|
19633
|
+
description: "Buy more usage ($5 or $10 packs, card or USDC) — opens the buy page.",
|
|
19634
|
+
handler: (_args, ctx) => buyCredits(opts, ctx)
|
|
19635
|
+
});
|
|
19547
19636
|
}
|
|
19548
19637
|
};
|
|
19549
19638
|
}
|
|
@@ -19590,6 +19679,7 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
19590
19679
|
baseUrl: opts.baseUrl,
|
|
19591
19680
|
getToken: () => opts.jwt
|
|
19592
19681
|
});
|
|
19682
|
+
const errorNoticeExtension = createErrorNoticeExtension();
|
|
19593
19683
|
const toolGuardExtension = createToolGuardExtension({
|
|
19594
19684
|
baseUrl: opts.baseUrl,
|
|
19595
19685
|
getToken: () => opts.jwt,
|
|
@@ -19604,6 +19694,7 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
19604
19694
|
adsExtension,
|
|
19605
19695
|
usageToolExtension,
|
|
19606
19696
|
buyToolExtension,
|
|
19697
|
+
errorNoticeExtension,
|
|
19607
19698
|
toolGuardExtension,
|
|
19608
19699
|
commandsExtension
|
|
19609
19700
|
];
|